Receiving frames from a wireless 433MHz temperature Sensor

Hi everyone,

Using a Lora 433Mhz (grove) transceiver I'm looking for reading my pellet stove temperature sensor.
I figured out I had to sniff the signal first to be able to understand how it's made.

The idea here is to trigger my ceiling fan when the temperature rises of a certain value.

Apparently the temperature sensor is supposed to send datas to the stove continuously but I doubt about it as I only received 8 packet over the night.

This morning I reset the sniffer and received 3 packets. The second and Third look uncomplete (isAck / PacketLen / PacketContents are missing). The first one is displaying a Packet content but it's unreadable.

(!)I have to say I'm not even sure this packets come from the Temp Sensor(!)

Rx Count~Rx@millis~LastRSSI~FromAddr~ToAddr~MsgId~HdrFlags~isAck~PacketLen~PacketContents
0 ~31560 ~16 ~ -88~ 70~ 208~ f4~ ~2296 ~⸮⸮⸮⸮⸮⸮⸮⸮

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Rx Count~Rx@millis~LastRSSI~FromAddr~ToAddr~MsgId~HdrFlags~isAck~PacketLen~PacketContents
1 ~ 5681~ 19~ -88~ 79~ 145~ da~
2 ~ -7914~ 34~ -88~ 166~ 71~ fa~

I have to say I had to look for quite a lot to find a sniffing code that "works" for me and I'm not 100% it fits my needs / hardware. This one may have been developed for another platfom (feather?)

Could you advise on what would be the next step for me to :

1- Ensure the sniffer is properly working and receiving everything it can.
2- Decode the Packet Content to read the temperature value.

// MIT License 
// Copyright 2017 LooUQ Incorportated.
// Many thanks to Adafruit and AirSpayce.

/* Example sketch to capture all packets on a LoRa (RF95) radio network and send them to the      
 *  serial port for monitoring or debugging a LoRa network.  
 *  
 *  Output MODE can be verbose or delimited
 *      - verbose sends output as readable text output with each field labeled
 *      - delimited sends output as a compressed text string, delimited by a char of your choice
 * Delimited is intended to be captured to a file on the serial host and displayed in an application
 * such as Excel or OpenOffice
 */

enum OutputMode { verbose, delimited };

/* Define your desired output format here */
OutputMode mode = delimited;
#define DELIMETER_CHAR '~'
/* end output format defintion */

#include <SPI.h>
#include <RH_RF95.h>
#include <stdio.h>

#define RH_FLAGS_ACK 0x80

/* for feather32u4
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 7
*/

/* for feather m0  */
#define RFM95_CS 8
#define RFM95_RST 4
#define RFM95_INT 3

/* for shield 
#define RFM95_CS 10
#define RFM95_RST 9
#define RFM95_INT 7
*/

/* Feather 32u4 w/wing
#define RFM95_RST     11   // "A"
#define RFM95_CS      10   // "B"
#define RFM95_INT     2    // "SDA" (only SDA/SCL/RX/TX have IRQ!)
*/

/* Feather m0 w/wing 
#define RFM95_RST     11   // "A"
#define RFM95_CS      10   // "B"
#define RFM95_INT     6    // "D"
*/

/* Teensy 3.x w/wing 
#define RFM95_RST     9   // "A"
#define RFM95_CS      10   // "B"
#define RFM95_INT     4    // "C"
*/







// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 434.0

// Singleton instance of the radio driver
//RH_RF95 rf95(RFM95_CS, RFM95_INT);
SoftwareSerial ss(5, 6);
RH_RF95 rf95(ss);
// Blink LED on packet receipt (Adafruit M0 here)
#define LED 13
 

int16_t rxCount = 0;                                        // packet counter
uint8_t rxBuffer[RH_RF95_MAX_MESSAGE_LEN];                  // receive buffer
uint8_t rxRecvLen;                                          // number of bytes actually received
char printBuffer[512] = "\0";                               // to send output to the PC
char formatString[] = {"%d~%d~%d~%d~%d~%d~%2x~%s~%d~%s"};
char legendString[] = "Rx Count~Rx@millis~LastRSSI~FromAddr~ToAddr~MsgId~HdrFlags~isAck~PacketLen~PacketContents";

void setup() 
{
    pinMode(LED, OUTPUT);     
    pinMode(RFM95_RST, OUTPUT);
    digitalWrite(RFM95_RST, HIGH);

    while (!Serial);
    Serial.begin(9600);
    delay(100);

  Serial.print("Feather LoRa Network Probe [Mode=");
  Serial.print(mode == verbose ? "verbose" : "delimeted");
  Serial.println("]");
  
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);
  }
  Serial.println("LoRa radio init OK!");

  if (!rf95.setFrequency(RF95_FREQ)) {                  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
      Serial.println("setFrequency failed");
      while (1);                                        // if can't set frequency, we are cooked!
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);

    // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

    // need to setPromiscuous(true) to receive all frames
    rf95.setPromiscuous(true);

    // set delimeter
    if (mode == delimited) {
        if (DELIMETER_CHAR != '~') {
            for (int i = 0; i < sizeof(formatString); i++)
            {
                if (formatString[i] == '~')
                    formatString[i] = DELIMETER_CHAR;
            }
            for (int i = 0; i < sizeof(legendString); i++)
            {
                if (legendString[i] == '~')
                    legendString[i] = DELIMETER_CHAR;
            }
        }
        Serial.println(legendString);
    }
}


void loop()
{
    // wait for a lora packet
    rxRecvLen = sizeof(rxBuffer);               // RadioHead expects max buffer, will update to received bytes
    digitalWrite(LED, LOW);

    if (rf95.available())
    { 
        digitalWrite(LED, HIGH);
        if (rf95.recv(rxBuffer, &rxRecvLen))
        {
            char isAck[4] = {""};
            if (rf95.headerFlags() & RH_FLAGS_ACK)
                memcpy(isAck, "Ack\0", 3);
            rxBuffer[rxRecvLen] = '\0';
            
            if (mode == delimited)
            {
                snprintf(printBuffer, sizeof(printBuffer), formatString, rxCount++, millis(), rf95.lastRssi(), rf95.headerFrom(), rf95.headerTo(), rf95.headerId(), rf95.headerFlags(), isAck, rxRecvLen, rxBuffer);
                Serial.println(printBuffer);
            }
            else
            {
                snprintf(printBuffer, sizeof(printBuffer), "Recv#:%d @ %d,   Signal(RSSI)= %d", rxCount++, millis(), rf95.lastRssi());
                Serial.println(printBuffer);
                snprintf(printBuffer, sizeof(printBuffer), " From: %d >> To: %d     MsgId: %d  Flags: %2x    %s", rf95.headerFrom(), rf95.headerTo(), rf95.headerId(), rf95.headerFlags(), isAck);
                Serial.println(printBuffer);
                snprintf(printBuffer, sizeof(printBuffer), "Bytes: %d => %s \r\n", rxRecvLen, rxBuffer);
                Serial.println(printBuffer);
            }
        }
    }
}

The LoRa device will only receive valid data from another LoRa device that is using the same LoRa frequency, bandwidth and spreading factor.

Are you sure your 'pellet stove temperature sensor' uses LoRa for one and second uses the same LoRa settings your using for the grove LoRa tranceiver ?

It is extremely unlikely that the stove uses LoRa radio. Use one of the cheap AM 433MHz radios, and decode the transmissions along these lines:

https://rayshobby.net/wordpress/reverse-engineer-wireless-temperature-humidity-rain-sensors-part-1/

Nico_del_Bernardo:
This morning I reset the sniffer and received 3 packets

I did recently discover an issue with some LoRa libraries where a 'missunderstanding' as to how the packet CRC is used can lead to random noise being accepted as valid data. The rate of these 'phantom packets' varies with the LoRa settings, but in some circumstances can be as high as 5-10 packets an hour.

I have not studied the RadioHead library in detail, but an initial look suggests it could possibly be succeptable to the problem.

Read about it here;

Phantom Packets 1

Phantom Packets 2

Phantom Packets 3

Hi srnet,

Thanks for you reply. I don't know if the temp sensor is running a LoRa and with what setting. However I can post a picture of the PCB if you feel it can be helpful!

Hi jremington,

Thank you for your help!
I'm running a Grove shield, do you think this one would make the deal?

Cheers,

Nico

srnet:
I did recently discover an issue with some LoRa libraries where a 'missunderstanding' as to how the packet CRC is used can lead to random noise being accepted as valid data. The rate of these 'phantom packets' varies with the LoRa settings, but in some circumstances can be as high as 5-10 packets an hour.

I have not studied the RadioHead library in detail, but an initial look suggests it could possibly be succeptable to the problem.

Read about it here;

Phantom Packets 1

Phantom Packets 2

Phantom Packets 3

Done, thanks! :slight_smile:

Nico_del_Bernardo:
Thanks for you reply. I don't know if the temp sensor is running a LoRa and with what setting. However I can post a picture of the PCB if you feel it can be helpful!

Cannot see why they would use LoRa, the range the sensor needs is only a few 10s of metres at worst, LoRa devices would be capable of 10 - 30 times that distance. .

Grove - 433MHz Simple RF Link Kit | Seeed Studio Wiki

The receiver would probably work, and a laptop with Audacity is all you need to follow the tutorial I linked.

LoRa is for very low bandwidth long distance data, not nearby sensors sampling at a high rate.

LoRa means Long Range.

srnet:
I did recently discover an issue with some LoRa libraries where a 'missunderstanding' as to how the packet CRC is used can lead to random noise being accepted as valid data. The rate of these 'phantom packets' varies with the LoRa settings, but in some circumstances can be as high as 5-10 packets an hour.

All CRCs are probabalistic, which means you should use extra authentication mechanism whenever a
phantom packet would be a real problem.

Since LoRa is designed to work at the threshold of the noise floor, phantom packets are likely and
the 6 bit header CRC isn't gaining much more than false confindence in a packet! Its 6 bit
to optimize the shortness of packets, but in reality its not much use and just means its wastes
6 bits as you have to have a proper CRC as well in any higher level protocol...

MarkT:
Since LoRa is designed to work at the threshold of the noise floor, phantom packets are likely and
the 6 bit header CRC isn't gaining much more than false confindence in a packet! Its 6 bit
to optimize the shortness of packets, but in reality its not much use and just means its wastes
6 bits as you have to have a proper CRC as well in any higher level protocol...

The LoRa designers had anticipated the potential problem, but it had not been appreciated by the library writers that you needed to check the 'packet has a CRC' flag bit in the header before you could believe the 'packet CRC invalid flag'. There was a mistaken assumption that if the 'packet CRC invalid flag' was not set, the packet was OK.

But my point is what use is a CRC that's that weak? I'd assert it is no use - in fact it just
causes the problems that a CRC is supposed to prevent as witnessed here.

MarkT:
But my point is what use is a CRC that's that weak? I'd assert it is no use - in fact it just
causes the problems that a CRC is supposed to prevent as witnessed here.

The packet CRC is 16 bit, you can use it or not.

You may well assert it's of no use, but I am not aware of any LoRa library that does not use it.

Well 6 +16 = 22, not too bad, but you have to reject all packets with any form of CRC fail before
any processing - and frankly for long distance comms using cryptographic authentication (a MAC)
is a very wise precaution, after all war-beaming is a lot easier then war-driving....