Hi
here is big part of main code and functions:
// %%%%%%%%%%%%%%%%%%%%%%%% VIKTIGE INNSTILLINGER %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#define sWrite 1 // 1 skriver ut til serial, 0 skriver minimalt ut til serial.
int mottagerVersjon = 53;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#include <WiFi.h>
#include <PubSubClient.h> // MQTT
#include <SPI.h> // the lora device is SPI based so load the SPI library
#include <SX127XLT.h> // include the appropriate library
#include "settings.h" // include the setiings file, frequencies, LoRa settings etc
SX127XLT LT; // create a library class instance called LT for LoRa
uint32_t RXpacketCount;
uint32_t errors;
uint8_t RXBUFFER[RXBUFFER_SIZE]; // create the buffer that received packets are copied into
uint8_t RXPacketL; // stores length of packet received
int16_t PacketRSSI; // stores RSSI of received packet
int8_t PacketSNR; // stores signal to noise ratio (SNR) of received packet
#include <Adafruit_GFX.h> // Libraries for OLED display
#include <Adafruit_SSD1306.h>
#include <Preferences.h> // for minnehåndtering
Preferences preferences; // Global definisjon
WiFiClient espClient;
PubSubClient client(espClient);
#if sWrite == 1 // 1: skriver til serial, 0: skriver ikke til serial
#define sp(x) Serial.print(x) // Serial.print definert som sp
#define spln(x) Serial.println(x) // Serial.println definert som spln
#else
#define sp(x)
#define spln(x)
#endif
//Variabler på sender- og mottagersiden
float vekt = 0;
int pakkeNr = 0;
float BStempKube = 0;
float BStempUte = 0;
float DHTtempKube = 0;
float DHTfuktKube = 0;
int alarmValue = 0;
int kubeNr = 0;
float volt = 0;
int senderVersjonNr = 0;
// Varabler på mottagersiden
int signalstyrke = 0;
String info = "x"; // for OLED M betyr les fra minne, :) er en ny pakke
int nesteForrige = 0; // variabel for å vise ny pakke, minne neste og forrige kube på OLED
int retryMQTT = 0; // Declare and initialize the retryMQTT connection variable
int maxRetryMQTT = 10;
const char* mqtt_username = "x"; // MQTT username virker 2023.07.05
const char* mqtt_password = "y"; // MQTT password virker 2023.07.05
const char* mqtt_clientID = "z"; // MQTT client ID, må være unikt pr IoT
String MQTTstatus = "_"; // For å skrive til serial at kobling til HA er OK
//******************* sett opp ssid2 til et nett fra mobiltelefon """""""""
const char* ssid1 = ""; // WiFi der mottager skal stå fast
const char* password1 = "";
const char* ssid2 = ""; // ekstra ved problemer, typisk mobilpassord
const char* password2 = "";
// LoRa receive payload
struct __attribute__((packed)) Payload { // denne må være identisk på sendersiden
float vekt;
int pakkeNr;
float BStempKube;
float BStempUte;
float DHTtempKube;
float DHTfuktKube;
int alarmValue;
int kubeNr;
float volt;
int senderVersjonNr;
};
// create a character arrays to store the string to mqtt, vil gjenbrukes for de ulike kubene nr 1,2 3 etc
char vektMsg[10];
char BStempKubeMsg[10];
char BStempUteMsg[10];
char DHTtempKubeMsg[10];
char DHTfuktKubeMsg[10];
char alarmValueMsg[10];
char kubeNrMsg[10];
char pakkeNrMsg[10];
char voltMsg[10];
char senderVersjonNrMsg[10];
char signalstyrkeMsg[10]; // kun på mottager side
//Prototype functions.
void oledVelkommen();
void connectToWiFi();
void lesMinne();
void skrivTilOled();
//OLED pins LoRa TTGO
#define OLED_SDA 21
#define OLED_SCL 22
#define OLED_RST 23
Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST);
// ######################################## VOID SETP #####################
void setup() {
Serial.begin(115200);
WiFi.begin(ssid1, password1);
oledVelkommen(); //velkomstskjerm
client.setServer("1xx", 1883); // MQTT server xx riktig ift mqtt mottak
// loraSetup();
SPI.begin();
//SPI beginTranscation is normally part of library routines, but if it is disabled in the library
//a single instance is needed here, so uncomment the program line below
//SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
//setup hardware pins used by device, then check if device is found
if (LT.begin(NSS, NRESET, DIO0, DIO1, DIO2, LORA_DEVICE))
{
Serial.print(F("LoRa mottager HiveMon, v ")); Serial.println(mottagerVersjon);
}
else
{
Serial.println(F("LoRa feila. Sjekk tilkoblingsdata."));
}
//The function call list below shows the complete setup for the LoRa device using the information defined in the
//Settings.h file.
//The 'Setup Lora device' list below can be replaced with a single function call;
//LT.setupLoRa(Frequency, Offset, SpreadingFactor, Bandwidth, CodeRate, Optimisation);
//***************************************************************************************************
//Setup Lora device
//***************************************************************************************************
LT.setMode(MODE_STDBY_RC); //got to standby mode to configure device
LT.setPacketType(PACKET_TYPE_LORA); //set for LoRa transmissions
LT.setRfFrequency(Frequency, Offset); //set the operating frequency
LT.calibrateImage(0); //run calibration after setting frequency
LT.setModulationParams(SpreadingFactor, Bandwidth, CodeRate, LDRO_AUTO); //set LoRa modem parameters
LT.setBufferBaseAddress(0x00, 0x00); //where in the SX buffer packets start, TX and RX
LT.setPacketParams(8, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL); //set packet parameters
LT.setSyncWord(LORA_MAC_PRIVATE_SYNCWORD); //syncword, LORA_MAC_PRIVATE_SYNCWORD = 0x12, or LORA_MAC_PUBLIC_SYNCWORD = 0x34
LT.setHighSensitivity(); //set for highest sensitivity at expense of slightly higher LNA current
LT.setDioIrqParams(IRQ_RADIO_ALL, IRQ_RX_DONE, 0, 0); //set for IRQ on RX done
//***************************************************************************************************
Serial.println();
LT.printModemSettings(); //reads and prints the configured LoRa settings, useful check
Serial.println("f");
LT.printOperatingSettings(); //reads and prints the configured operting settings, useful check
Serial.println();
Serial.println();
LT.printRegisters(0x00, 0x4F); //print contents of device registers, normally 0x00 to 0x4F
Serial.println();
Serial.println();
Serial.print(F("Receiver ready - RXBUFFER_SIZE "));
Serial.println(RXBUFFER_SIZE);
Serial.println();
// Try to connect to the first of 2 Wi-Fi network within 10 seconds
connectToWiFi(); // Prøver å koble til Wi-Fi ved oppstart
}
void loop() {
if (WiFi.status() != WL_CONNECTED) { // Check if already connected to WiFi, om ikke koble til på nytt
connectToWiFi();
Serial.println("Koblet til WiFi på nytt!");
}
if (!client.connected()) { // dersom frakoblet så kobler til på nytt
delay(100); // sjekker om delay gjør MQTT mer stabil
while (!client.connected() && retryMQTT < maxRetryMQTT) {
Serial.println("Kobler til MQTT (på nytt) ...");
if (client.connect(mqtt_clientID, mqtt_username, mqtt_password)) {
Serial.print("retryMQTT (a)= "); Serial.println(retryMQTT); // teller
Serial.println("MQTT koblet til HA! IP 192.168.0.60:1883, web :8123");
delay(1000);
retryMQTT = 0; // Reset the retry count if the connection is successful
MQTTstatus = "Koblet til HA";
} else {
Serial.print("retryMQTT (b)= "); Serial.println(retryMQTT);
Serial.print("Feila å koble til MQTT, Return Code = ");
Serial.println(client.state());
delay(500);
retryMQTT++;
MQTTstatus = "Ikke koblet til HA, RC = " + client.state();
if (retryMQTT == maxRetryMQTT) {
spln("ESP restarter");
delay(5000);
ESP.restart(); // ###################### behold denne muligheten se på versjon tidligere
}
}
}
}
client.loop(); // MQTT loop
RXPacketL = LT.receive(RXBUFFER, RXBUFFER_SIZE, 60000, WAIT_RX); //wait for a packet to arrive with 60seconds (60000mS) timeout
PacketRSSI = LT.readPacketRSSI(); //read the recived RSSI value
PacketSNR = LT.readPacketSNR(); //read the received SNR value
if (RXPacketL == 0) { //if the LT.receive() function detects an error, RXpacketL is 0{
packet_is_Error();
}
else {
packet_is_OK();
}
} // End void loop
Settings.h
//******* Setup hardware pin definitions here ! ***************
//These are the pin definitions for one of my own boards, the Easy Pro Mini,
//be sure to change the definitions to match your own setup. Some pins such as DIO1,
//DIO2, BUZZER may not be in used by this sketch so they do not need to be
//connected and should be set to -1.
#define NSS 18 //select pin on LoRa device
#define NRESET 14 //reset pin on LoRa device
#define LED1 -1 //on board LED, high for on
#define DIO0 26 //DIO0 pin on LoRa device, used for RX and TX done
#define DIO1 -1 //DIO1 pin on LoRa device, normally not used so set to -1
#define DIO2 -1 //DIO2 pin on LoRa device, normally not used so set to -1
#define BUZZER -1 //pin for buzzer, on when logic high
#define LORA_DEVICE DEVICE_SX1278 //we need to define the device we are using
//******* Setup LoRa Parameters Here ! ***************
//LoRa Modem Parameters
const uint32_t Frequency = 868000000; //frequency of transmissions in hertz
const uint32_t Offset = 0; //offset frequency for calibration purposes
const uint8_t Bandwidth = LORA_BW_125; //LoRa bandwidth
const uint8_t SpreadingFactor = LORA_SF7; //LoRa spreading factor
const uint8_t CodeRate = LORA_CR_4_5; //LoRa coding rate
const uint8_t Optimisation = LDRO_AUTO; //low data rate optimisation setting, normally set to auto
const int8_t TXpower = 2; //LoRa transmit power in dBm
const uint16_t packet_delay = 1000; //mS delay between packets
#define RXBUFFER_SIZE 50 //32 //RX buffer size
/*******************************************************************************************************
Programs for Arduino - Copyright of the author Stuart Robinson - 02/03/20
This program is supplied as is, it is up to the user of the program to decide if the program is
suitable for the intended purpose and free from errors.
*******************************************************************************************************/
CRC_functions and other functions
void packet_is_OK() {
uint16_t IRQStatus, localCRC;
IRQStatus = LT.readIrqStatus();
RXpacketCount++;
// Extract payload without modifying its byte order
Payload payload;
memcpy(&payload, RXBUFFER, sizeof(Payload));
//Serial.print(F("Received data: "));
//printReceivedPayload(payload); // Add this line to print raw bytes
spln();
localCRC = LT.CRCCCITT(reinterpret_cast<uint8_t*>(&payload), sizeof(Payload), 0xFFFF);
sp(F("CRC: ")); Serial.println(localCRC, HEX); // dette virker ikke sp(localCRC); sp(", "); spln(HEX);
sp(F("RSSI: ")); sp(PacketRSSI); spln(F(" dBm"));
sp(F("SNR: ")); spln(PacketSNR);
sp(F("Length: ")); spln(RXPacketL);
sp(F("Packets: ")); spln(RXpacketCount);
sp(F("Errors: ")); spln(errors);
sp(F("IRQreg: ")); Serial.println(IRQStatus, HEX);
spln("---------------------------------------------");
if (payload.vekt > 150) { // feilhåndtering om vekt blir gærn, holder OLED ryddig:
payload.vekt = -99;
}
if (payload.alarmValue == 1) { // sjekker om alarm
Serial.println("Alarm!!! "); // skriver til OLED
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(2);
display.setCursor(20, 1); display.print("ALARM"); // 15 fra venstre, 21 fra topp
display.display(); // selve skrivingen til display fra buffer
delay(1000);
}
else {
payload.alarmValue = 9; // kan ikke bruke 0 pga HA, sørger for å sende verdi til HA og ikke nan
Serial.print(F(" alarmValue: ")); Serial.println(payload.alarmValue);
}
// DYNAMISK tildeling av topic string ift kubeNr slik at hver pakke kommer til riktig HA system
String topicKubeNr = String(payload.kubeNr);
String vektTopic = "bikuber/kube" + topicKubeNr + "/vekt"; // riktig
String pakkeNrTopic = "bikuber/kube" + topicKubeNr + "/pakkeNr";
String BStempKubeTopic = "bikuber/kube" + topicKubeNr + "/BStempKube";
String BStempUteTopic = "bikuber/kube" + topicKubeNr + "/BStempUte";
String DHTtempKubeTopic = "bikuber/kube" + topicKubeNr + "/DHTtempKube";
String DHTfuktKubeTopic = "bikuber/kube" + topicKubeNr + "/DHTfuktKube";
String alarmValueTopic = "bikuber/kube" + topicKubeNr + "/alarmValue";
String kubeNrTopic = "bikuber/kube" + topicKubeNr + "/kubeNr";
String voltTopic = "bikuber/kube" + topicKubeNr + "/volt";
String senderVersjonNrTopic = "bikuber/kube" + topicKubeNr + "/senderVersjonNr";
String signalstyrkeTopic = "bikuber/kube" + topicKubeNr + "/signalstyrke";
// Convert payload into Msg strings. PASS PÅ INT VS FLOAT %d vs %f
snprintf(vektMsg , 10, " %.1f" , payload.vekt); //riktig
snprintf(pakkeNrMsg , 10, " %d" , payload.pakkeNr);
snprintf(BStempKubeMsg , 10, " %.1f" , payload.BStempKube);
snprintf(BStempUteMsg , 10, " %.1f" , payload.BStempUte);
snprintf(DHTtempKubeMsg , 10, " %.1f" , payload.DHTtempKube);
snprintf(DHTfuktKubeMsg , 10, " %.lf" , payload.DHTfuktKube);
snprintf(alarmValueMsg , 10, " %.d" , payload.alarmValue);
snprintf(kubeNrMsg , 10, " %.d" , payload.kubeNr);
snprintf(voltMsg , 10, " %.1f" , payload.volt);
snprintf(senderVersjonNrMsg , 10, " %d" , payload.senderVersjonNr);
snprintf(signalstyrkeMsg , 10, " %.d" , PacketRSSI);
// Publish message to Home Assistant, OLED and serial, basert på kubeNr
// sorterer ut data, kubeNr, som er utenfor scope
client.publish(vektTopic.c_str() , vektMsg); // riktig
client.publish(pakkeNrTopic.c_str() , pakkeNrMsg);
client.publish(BStempKubeTopic.c_str() , BStempKubeMsg);
client.publish(BStempUteTopic.c_str() , BStempUteMsg);
client.publish(DHTtempKubeTopic.c_str() , DHTtempKubeMsg);
client.publish(DHTfuktKubeTopic.c_str() , DHTfuktKubeMsg);
client.publish(alarmValueTopic.c_str() , alarmValueMsg);
client.publish(kubeNrTopic.c_str() , kubeNrMsg);
client.publish(voltTopic.c_str() , voltMsg);
client.publish(senderVersjonNrTopic.c_str(), senderVersjonNrMsg);
client.publish(signalstyrkeTopic.c_str() , signalstyrkeMsg);
sp("MQTT publisert til HA path: bikuber/kube" + topicKubeNr + "/" );
vekt = payload.vekt; // legger payload inn i variablene, burde være unødig da de ligger i myPayload
pakkeNr = payload.pakkeNr;
BStempKube = payload.BStempKube;
BStempUte = payload.BStempUte;
DHTtempKube = payload.DHTtempKube;
DHTfuktKube = payload.DHTfuktKube;
alarmValue = payload.alarmValue;
kubeNr = payload.kubeNr;
volt = payload.volt;
senderVersjonNr = payload.senderVersjonNr;
signalstyrke = PacketRSSI;
// Save the values to preferences og namspace pr kubeNr
String kubeNrStringPut = String(kubeNr); // var String(kubeNr);konverterer int kubeNr til å blir en namspace
preferences.begin (kubeNrStringPut.c_str(), false); // namspace er dynamisk: kubeNrString.c_str() typisk "my-app", her er det "1"
preferences.putFloat("vekt", payload.vekt);
preferences.putInt ("pakkeNr", payload.pakkeNr);
preferences.putFloat("BStempKube", payload.BStempKube);
preferences.putFloat("BStempUte", payload.BStempUte);
preferences.putFloat("DHTtempKube", payload.DHTtempKube);
preferences.putFloat("DHTfuktKube", payload.DHTfuktKube);
preferences.putInt ("alarmValue", payload.alarmValue);
preferences.putInt ("kubeNr", payload.kubeNr);
preferences.putFloat("volt", payload.volt);
preferences.putInt ("senderVersjonNr", payload.senderVersjonNr);
preferences.putInt ("signalstyrke", PacketRSSI);
preferences.end();
info = ":)"; // for OLED *SMIL* dersom ny pakke
skrivTilOled(kubeNr);
skrivTilSerial(kubeNr);
}
// denne er ikke i bruk
void printReceivedPayload(const Payload& payload) {
Serial.print(F("Raw Bytes: "));
for (size_t i = 0; i < sizeof(Payload); i++) {
Serial.print(reinterpret_cast<const uint8_t*>(&payload)[i], HEX);
Serial.print(" ");
}
Serial.println();
Serial.print(F(" vekt: a ")); Serial.println(payload.vekt);
Serial.print(F(" pakkeNr: ")); Serial.println(payload.pakkeNr);
Serial.print(F(" BStempKube: ")); Serial.println(payload.BStempKube);
Serial.print(F(" BStempUte: ")); Serial.println(payload.BStempUte);
Serial.print(F(" DHTtempKube: ")); Serial.println(payload.DHTtempKube);
Serial.print(F(" DHTfuktKube: ")); Serial.println(payload.DHTfuktKube);
Serial.print(F(" alarmValue: ")); Serial.println(payload.alarmValue);
Serial.print(F(" volt: ")); Serial.println(payload.volt);
Serial.print(F(" sender-versjon: ")); Serial.println(payload.senderVersjonNr);
}
void packet_is_Error()
{
uint16_t IRQStatus;
IRQStatus = LT.readIrqStatus(); //read the LoRa device IRQ status register
printElapsedTime(); //print elapsed time to Serial Monitor
if (IRQStatus & IRQ_RX_TIMEOUT) //check for an RX timeout
{
Serial.println(F(" RXTimeout"));
}
else
{
errors++;
Serial.print(F(" Packet Error Error Error Error Error Error Error Error Error Error Error "));
Serial.print(F(" RSSI(dBm): ")); Serial.println(PacketRSSI);
Serial.print(F(" SNR(dB): ")); Serial.println(PacketSNR);
Serial.print(F(" Length: ")); Serial.println(LT.readRXPacketL()); //get the device packet length
Serial.print(F(" Packets: ")); Serial.println(RXpacketCount);
Serial.print(F(" Errors: ")); Serial.println(errors);
Serial.print(F(" IRQreg: ")); Serial.print(IRQStatus, HEX);
LT.printIrqStatus(); //print the names of the IRQ registers set
}
}
void printElapsedTime()
{
float seconds;
seconds = millis() / 1000;
Serial.print(F("Elapsed time: ")); Serial.print(seconds, 2); Serial.println(F(" s"));
}