#include <FastCRC.h>
// Function to generate a random temperature reading
float generateTemperature() {
// Generate a random temperature between 0 and 100 degrees Celsius
return random(0, 100);
}
// Function to extract the CRC value from the received message
uint32_t extractCRC(String message) {
int crcIndex = message.lastIndexOf('*');
String crcString = message.substring(crcIndex + 1);
return strtoul(crcString.c_str(), NULL, 16);
}
// Function to verify the CRC of the received message
bool verifyCRC(String message, uint32_t receivedCRC) {
FastCRC32 crc;
uint32_t calculatedCRC = crc.crc32((const uint8_t*)message.c_str(), message.length() - 1);
return (calculatedCRC == receivedCRC);
}
void setup() {
Serial.begin(9600);
randomSeed(analogRead(A0)); // Seed the random number generator with an analog input
}
void loop() {
// Generate a random temperature reading
float temperature = generateTemperature();
// Create the LoRa message string
String messagePayload = "Temperature: " + String(temperature) + " C";
// Calculate the CRC of the message
FastCRC32 crc;
uint32_t calculatedCRC = crc.crc32((const uint8_t*)messagePayload.c_str(), messagePayload.length());
// Append the CRC to the message
messagePayload += " *";
messagePayload += String(calculatedCRC, HEX);
// Display the message and CRC for debugging purposes
Serial.print("Message: ");
Serial.println(messagePayload);
Serial.print("CRC: ");
Serial.println(calculatedCRC, HEX);
// Simulate LoRa transmission and reception
// ...
// Receive the LoRa message
String receivedMessage = ""; // Replace this with your code to receive the LoRa message
// Extract the received CRC from the message
uint32_t receivedCRC = extractCRC(receivedMessage);
// Verify the CRC of the received message
bool crcMatch = verifyCRC(receivedMessage, receivedCRC);
if (crcMatch) {
// CRC verification passed
// Strip the CRC from the received message
int crcIndex = receivedMessage.lastIndexOf('*');
String messagePayload = receivedMessage.substring(0, crcIndex);
// Process the message payload
// ...
Serial.println("Message payload: " + messagePayload);
} else {
// CRC verification failed
// Handle the error or discard the message
// ...
Serial.println("CRC verification failed. Discarding message.");
}
// Delay or other operations
delay(5000);
}
// Receive the LoRa message
String receivedMessage = ""; // Replace this with your code to receive the LoRa message
// Extract the received CRC from the message
uint32_t receivedCRC = extractCRC(receivedMessage);
and your function assumes there is a valid message including a star '*' character followed by a uint32_t represented in HEX/ASCII... which is not the case.
your verifyCRC() will also fail as you should not take into account the star and what's after
but as @srnet said, why do you want to do that yourself ?....
so something like this should no longer fail and check the CRC correctly as long as the message is correct (I'm not testing for the actual well formed message which you should do, the star might not be there at all if you expect data corruption)
#include <FastCRC.h>
// Function to generate a random temperature reading
float generateTemperature() {
// Generate a random temperature between 0 and 100 degrees Celsius
return random(0, 100);
}
// Function to extract the CRC value from the received message
uint32_t extractCRC(String& message) {
int crcIndex = message.lastIndexOf('*');
String crcString = message.substring(crcIndex + 1);
uint32_t crc = strtoul(crcString.c_str(), NULL, 16);
Serial.print("crcString = "); Serial.println(crcString);
Serial.print("crcString value = 0x"); Serial.println(crc, HEX);
return crc;
}
// Function to verify the CRC of the received message
bool verifyCRC(String& message, uint32_t receivedCRC) {
FastCRC32 crc;
int crcIndex = message.lastIndexOf('*');
uint32_t calculatedCRC = crc.crc32((const uint8_t*)message.c_str(), crcIndex - 1);
return (calculatedCRC == receivedCRC);
}
void setup() {
Serial.begin(9600);
randomSeed(analogRead(A0)); // Seed the random number generator with an analog input
}
void loop() {
// Generate a random temperature reading
float temperature = generateTemperature();
// Create the LoRa message string
String messagePayload = "Temperature: " + String(temperature) + " C";
// Calculate the CRC of the message
FastCRC32 crc;
uint32_t calculatedCRC = crc.crc32((const uint8_t*)messagePayload.c_str(), messagePayload.length());
// Append the CRC to the message
messagePayload += " *";
messagePayload += String(calculatedCRC, HEX);
// Display the message and CRC for debugging purposes
Serial.print("Message: ");
Serial.println(messagePayload);
Serial.print("CRC: ");
Serial.println(calculatedCRC, HEX);
// Simulate LoRa transmission and reception
// ...
// Receive the LoRa message
String receivedMessage = messagePayload; // Replace this with your code to receive the LoRa message
// Extract the received CRC from the message
uint32_t receivedCRC = extractCRC(receivedMessage);
// Verify the CRC of the received message
bool crcMatch = verifyCRC(receivedMessage, receivedCRC);
if (crcMatch) {
// CRC verification passed
// Strip the CRC from the received message
int crcIndex = receivedMessage.lastIndexOf('*');
String messagePayload = receivedMessage.substring(0, crcIndex);
// Process the message payload
// ...
Serial.println("CRC verification OK. Handling message.");
Serial.println("Message payload: " + messagePayload);
} else {
// CRC verification failed
// Handle the error or discard the message
// ...
Serial.println("CRC verification failed. Discarding message.");
}
// Delay or other operations
delay(5000);
}
(I avoided duplicating the strings in function calls by adding the & to pass the string by reference)
they still might be bogus. One way to check it out is that you'll see the CRC is correct for those messages with wrong measures, because the CRC is only there to check the integrity of the message and won't fix an issue when performing the sampling
On the sender side, if you have an idea of the expected range, you could discard outliers
This is something I have in mind, but this scale (bee hive) is running all year, and weight is changing from 15 kg to 100 kg . So I was hoping to send "only correct" values.
I understand that crc dont help me with wrong values, but it will sort out some noise.
But I must find a way to detect and remove bogus values before I send them.
I'm working on it, step 1 is to look into my median calculus, if I can improve it.
Next is to filter, as you say, the worst range errors.
From http://beep.nl (millions developing money from EU) I have seen that they also use HX711, and they don't have this crazy readings presented, so yes, I must up the code.
If you have any tip pleas bring it on
If you need a bee monitor, i will provide HW for you .... in return for "filtercode"
as mentioned before, I have some crazy values coming to my receiver system, loads up to 40000 kg and I'm not sure of the origin of these readings.
So If you manage to find my mistakes I'm happy to receive your help!
I use ESP32 WROOM.
Here is my schematic for my monitor, sender side:
Here is my code for reading a load cell ( I have condensed it to focus on my load readings and median calculations, also added a random function):
// monoitor
int LoRaIntervall = 10; // Lora pkg sec
double data = 0;
#include <SPI.h>
#include <Wire.h> // for å lese I2C, muligens for LoRa
#include <math.h>
#include <algorithm> // Allows sort function
#include <LoRa.h>
#include "HX711.h" // This library can be obtained here http://librarymanager/All#Avia_HX711 https://github.com/bogde/HX711
#include <DHT.h> // DHT11 aidafruit
#define DHTPIN 12 // Digital pin connected to the DHT sensor Pin 15 can work but DHT must be disconnected during program upload.
#define DHTTYPE DHT11 // DHT 11 eller 22
#define LB2KG 0.45352 // omregningsfaktor
#define CALWEIGHT 25.3 // kjent vekt i kg
#define DEFAULT_CALIFACTOR -9679,0
#define number_of_digits 3 // Desimaler for vektavlesing
DHT dht(DHTPIN, DHTTYPE);
//Measuring runtime for when if mills kick in, this to delay sending of packets
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000; //slett?
// Function calls
// float medianFilter(float input) // bør denne også med i calls?
void sendReadings();
// hx711 pins:
#define LOADCELL_DOUT_PIN 21
#define LOADCELL_SCK_PIN 22
HX711 scale;
float calibration_factor = -9669.59; // testvekt
float currentOffset = -314123.00;
float calYesNo = 0;
//define the pins used by the LoRa transceiver module TTGO OLED ESP32:
#define SCK 5
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 14
#define DIO0 26
#define BAND 868E6
int packetID = 0; //packet counter, reset after boot
//Variables to store temperature, humidity, weight and tare switch status, hive name
float temperatureHive = 0;
float temperatureOut = 0;
float humidity = 0;
float weight = 0;
float tareValue = 0;
float alarmValue = 0; // Nullstilles kun ved å boot senderen
float hiveNr = 1; // Kube nr UNIK verdi
// Define Switches
const int switchAlarm = 36; //17; // select the input pin for the switch Alarm må være interupt el for å gå ut av sleep
// const int switchReset = EN; // this is a physical input connection high/low How to make a
int switchTareValue = 0; // variable to store the value coming from the sensor
unsigned long tareStartTime = 0; // variable to store the start time
int switchReset = 1; //
int switchResetValue = 2;
//int switchAlarm = 3; // select the input pin for the switch
int previousState = LOW;
//Median filtering of weight
float window[5]; // array to hold the sorted values in the window
int indeks = 0; // indeks of the current value
int medianCount = 0;
float weight_median = 0;
//test
int teller = 1;
const int buttonPressTime = 5000; // wait time in milliseconds
const int alarmPressTime = 5000;
bool buttonPressed = false; // Keep track of whether the button has been pressed
// #####################################################################
void setup() {
Serial.begin(115200); delay(500);
Serial.println();
Serial.println("Starts...");
//tone(piezoPin, 2000, 500);
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
scale.set_scale(); delay(500);
// for debug purpose
randomSeed(analogRead(A0));
//Setup for temperature and humidity functionality
//dht.begin();
//Setup for LoRa
Serial.println("LoRa transivertest utføres");
SPI.begin(SCK, MISO, MOSI, SS);
LoRa.setPins(SS, RST, DIO0);
if (!LoRa.begin(BAND)) {
Serial.println("LoRa transivertest error!");
while (1);
}
Serial.print("LoRa initisiert!, cal fact: ");
Serial.println(calibration_factor);
scale.set_scale(calibration_factor / LB2KG); // denne omregningen tror jeg er unødig om en kalibrerer uten denne
delay(1500);
}
// #####################################################################
void loop() {
unsigned long currentTime = millis();
if (currentTime - previousTime >= 3000) { //Change this value to publish at a different interval. 4 pkg pr loop, 60sec/4 pkg = 15 sec
previousTime = currentTime;
// DEBUG Function to generate a random double number (Kg) within a given range
weight_median = medianFilter((((double)random(1000000) / 1000000.0) * (65.34 - 44.45) + 44.45)); //
//Serial.print("Variable weigth_median: ");
//Serial.println(weight_median);
Serial.println("'window' after sort: ");
for (int i = 0; i < 5; i++) { // display the values after median calculus
Serial.print(" | ");
Serial.print(window[i]);
}
Serial.println(" |");
sendReadings();
Serial.print(" ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ counter: ");
Serial.println(teller);
teller = teller + 1;
delay(500);
}
}
/**************************************************************************************************/
// FUNCTIONS
float medianFilter(float input) {
float median = 0.0;
// add the current value to the window:
window[indeks] = input;
//Serial.print("Input inni window array er: ");
//Serial.println(window[indeks]);
Serial.print("Variable weigth_median: ");
Serial.println(weight_median);
Serial.print("'window' before sort, index: ");
Serial.println(indeks);
for (int i = 0; i < 5; i++) {
Serial.print(" | ");
Serial.print(window[i]);
}
Serial.println(" |");
// advance to the next position in the array:
indeks = indeks + 1;
// if we're at the end of the array, go back to the beginning:
if (indeks >= 5) {
indeks = 0;
}
// sort the values in the window:
float* sortedArray = window;
mySort(sortedArray, 5);
// the median value is the middle value in the sorted array:
if (medianCount == 0) {
median = sortedArray[4];
medianCount = medianCount + 1;
}
else if (medianCount == 1) {
median = (sortedArray[4] + sortedArray[3]) / 2;
medianCount = medianCount + 1;
}
else if (medianCount == 2) {
median = sortedArray[3];
medianCount = medianCount + 1;
}
else if (medianCount == 3) {
median = (sortedArray[3] + sortedArray[2]) / 2;
medianCount = medianCount + 1;
}
else {
median = sortedArray[2];
}
// return the median value:
//Serial.print("Median inside funksjonen is: ");
//Serial.println(median);
return median;
}
/**************************************************************************************************/
void mySort(float* array, int size) {
for (int i = 0; i < size - 1; i++) {
for (int j = i + 1; j < size; j++) {
if (array[i] > array[j]) {
// swap the elements if they are out of order:
float temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
}
/**************************************************************************************************/
void sendReadings() {
//Serial.println("function send reading");
//debug fix value when not connected to DHT sensor
// temperatureHive = 17.2;
temperatureOut = 7.4;
// humidity = 50.1;
String LoRaMessage = String(packetID) + "/" + String(temperatureHive) + "&" + String(temperatureOut) + "@" + String(humidity) + "£" + String(weight_median) + "#" + String(alarmValue) + "%" + String(hiveNr) + "¤";
//Send LoRa packet to receiver
packetID++; //incremets LoRa packet +1
LoRa.beginPacket();
LoRa.print(LoRaMessage);
LoRa.endPacket();
// debug
// Print to serial monitor
//Serial.println("LoRa pakke sendt");
//Serial.println();
// Serial.print ("Kalibreringsfaktor: "); Serial.println(calibration_factor);
Serial.println("LoRa msg in air:");
//Serial.println((String)"Kubenr: " + hiveNr);
Serial.println((String)"Weight g (median): " + weight_median);
//Serial.println((String)"Temperatur kube: " + temperatureHive);
Serial.println((String)"Temperatur out: " + temperatureOut);
//Serial.println((String)"Luftfuktighet: " + humidity);
//Serial.println((String)"Alarm 1=Alarm: " + alarmValue);
delay(10); // due to missing characters on serial print
//Serial.print ("Pakke ID: "); Serial.println(packetID);
//Serial.println("Mon versjon: Sender_ESP32_v50.1");
//Serial.println("--------------------------------------------");
//Serial.println("ID TH TU RH% vekt alrm kubeNr"); // for debugging
//Serial.println(LoRaMessage); // for debugging
//Serial.println("============================================");
Serial.println();
}