├── .gitignore ├── README.md ├── lora-sender └── lora-sender.ino └── lora-to-mqtt └── lora-to-mqtt.ino /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aaronpk/LoRa-Experiments/main/README.md -------------------------------------------------------------------------------- /lora-sender/lora-sender.ino: -------------------------------------------------------------------------------- 1 | #include "heltec.h" 2 | 3 | #define BAND 915E6 4 | #define USERNAME "aaronpk" 5 | #define DEVICE "bike" 6 | 7 | int counter = 0; 8 | 9 | void setup() { 10 | Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/); 11 | Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); 12 | Heltec.display->setFont(ArialMT_Plain_16); 13 | //LoRa.setSpreadingFactor(6); 14 | LoRa.enableCrc(); 15 | //LoRa.setSignalBandwidth(125E3); 16 | } 17 | 18 | void loop() { 19 | Serial.print("Sending packet: "); 20 | Serial.println(counter); 21 | 22 | digitalWrite(25, HIGH); 23 | 24 | // Show the count on the screen 25 | Heltec.display->clear(); 26 | Heltec.display->setColor(WHITE); 27 | Heltec.display->drawString(0, 0, String(USERNAME)); 28 | Heltec.display->drawString(0, 16, "device: "+String(DEVICE)); 29 | Heltec.display->drawString(0, 32, "id: "+String(counter)); 30 | Heltec.display->display(); 31 | 32 | // Send the LoRa packet 33 | LoRa.beginPacket(); 34 | LoRa.setTxPower(14, RF_PACONFIG_PASELECT_PABOOST); 35 | LoRa.print("{\"username\":\""+String(USERNAME)+"\",\"device\":\""+String(DEVICE)+"\",\"id\":\""+String(counter)+"\"}"); 36 | LoRa.endPacket(); 37 | 38 | counter++; 39 | 40 | // Heltec.display->setColor(BLACK); 41 | // Heltec.display->fillRect(112, 16, 8, 8); 42 | // Heltec.display->display(); 43 | digitalWrite(25, LOW); 44 | 45 | delay(2000); 46 | } 47 | -------------------------------------------------------------------------------- /lora-to-mqtt/lora-to-mqtt.ino: -------------------------------------------------------------------------------- 1 | #include "heltec.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* wifi credentials */ 8 | #define WIFISSID "" 9 | #define WIFIPASS "" 10 | /* point this at your MQTT server */ 11 | #define MQTTSERVER "" 12 | #define MQTTPORT 1883 13 | /* 915E6 is 915Mhz band for the US */ 14 | #define BAND 915E6 15 | /* identifier for this receiver */ 16 | #define STATIONID "" 17 | 18 | /* 19 | * MQTT messages will be formatted as: 20 | * topic: lora/msg/[station]/[rssi] 21 | * payload: passthru from receiver, unparsed 22 | */ 23 | 24 | WiFiMulti WiFiMulti; 25 | WiFiClient wifiClient; 26 | PubSubClient mqttClient(wifiClient); 27 | 28 | DynamicJsonDocument packet(1000); 29 | 30 | void setup() { 31 | Serial.begin(115200); 32 | delay(10); 33 | 34 | initLora(); 35 | initWifi(); 36 | initMqtt(); 37 | initDisplay(); 38 | showWaitingMessage(); 39 | } 40 | 41 | void drawMessage(String msg, int line=0) { 42 | if(line == 0) { 43 | Heltec.display->clear(); 44 | Heltec.display->setColor(WHITE); 45 | } 46 | Heltec.display->drawString(0, line*12, msg); 47 | } 48 | 49 | void displayMessage() { 50 | Heltec.display->display(); 51 | } 52 | 53 | void initLora() { 54 | Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/); 55 | //LoRa.setSpreadingFactor(6); 56 | //LoRa.setSignalBandwidth(125E3); 57 | //LoRa.enableCrc(); 58 | } 59 | 60 | void initWifi() { 61 | WiFiMulti.addAP(WIFISSID, WIFIPASS); 62 | drawMessage("Connecting to WiFi..."); 63 | drawMessage("SSID: "+String(WIFISSID), 1); 64 | displayMessage(); 65 | 66 | int wifiCounter = 0; 67 | while(WiFiMulti.run() != WL_CONNECTED) { 68 | delay(500); 69 | } 70 | 71 | drawMessage("Connected to WiFi"); 72 | drawMessage("SSID: "+String(WIFISSID), 1); 73 | drawMessage("IP: "+WiFi.localIP().toString(), 2); 74 | displayMessage(); 75 | Serial.println(WiFi.localIP()); 76 | delay(1000); 77 | } 78 | 79 | void initMqtt() { 80 | mqttClient.setServer(MQTTSERVER, MQTTPORT); 81 | mqttReconnect(); 82 | delay(1000); 83 | } 84 | 85 | void initDisplay() { 86 | Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT); 87 | Heltec.display->setFont(ArialMT_Plain_10); 88 | } 89 | 90 | void showWaitingMessage() { 91 | drawMessage("Listening for data..."); 92 | drawMessage("WiFi: "+String(WIFISSID), 1); 93 | drawMessage("MQTT: "+String(MQTTSERVER)+":"+String(MQTTPORT), 2); 94 | drawMessage("IP: "+WiFi.localIP().toString(), 3); 95 | drawMessage("Station: "+String(STATIONID), 4); 96 | displayMessage(); 97 | } 98 | 99 | void mqttReconnect() { 100 | Serial.println("Reconnecting to MQTT"); 101 | // Loop until we're reconnected 102 | while (!mqttClient.connected()) { 103 | drawMessage("Connecting to MQTT..."); 104 | drawMessage(String(MQTTSERVER)+":"+String(MQTTPORT), 1); 105 | displayMessage(); 106 | // Attempt to connect 107 | if (mqttClient.connect(STATIONID)) { 108 | Serial.println("connected to MQTT"); 109 | char mqttkey[100]; 110 | sprintf(mqttkey, "lora/init/%s", STATIONID); 111 | Serial.println("Publishing "+String(mqttkey)); 112 | mqttClient.publish(mqttkey, "connected"); 113 | } else { 114 | Serial.print("failed, rc="); 115 | Serial.print(mqttClient.state()); 116 | Serial.println(" try again in 5 seconds"); 117 | // Wait 5 seconds before retrying 118 | delay(5000); 119 | } 120 | } 121 | drawMessage("Connected to MQTT server"); 122 | drawMessage(String(MQTTSERVER)+":"+String(MQTTPORT), 1); 123 | displayMessage(); 124 | } 125 | 126 | char message[256]; // max LoRa packet length 127 | 128 | unsigned long receivedTimestamp = 0; 129 | 130 | void loop() { 131 | if(!mqttClient.connected()) { 132 | mqttReconnect(); 133 | showWaitingMessage(); 134 | } 135 | 136 | int packetSize = LoRa.parsePacket(); 137 | if(packetSize) { 138 | digitalWrite(25, HIGH); 139 | 140 | Serial.print("Received packet '"); 141 | // read packet into string 142 | int i = 0; 143 | while (LoRa.available() && i <= 255) { 144 | message[i++] = (char)LoRa.read(); 145 | } 146 | message[i] = '\0'; 147 | 148 | // send to MQTT 149 | char mqttkey[100]; 150 | sprintf(mqttkey, "lora/msg/%s/%d/%.2f", STATIONID, LoRa.packetRssi(), LoRa.packetSnr()); 151 | Serial.println("Publishing "+String(mqttkey)); 152 | mqttClient.publish(mqttkey, message); 153 | 154 | Serial.println(String(message)+"' with RSSI "+String(LoRa.packetRssi())); 155 | 156 | // parse the JSON 157 | DeserializationError err = deserializeJson(packet, message); 158 | if(err) { 159 | drawMessage("Packet data was not JSON"); 160 | displayMessage(); 161 | } else { 162 | const char* username = packet["username"].as(); 163 | const char* device = packet["device"].as(); 164 | const char* uniqueid = packet["id"].as(); 165 | drawMessage("username: "+String(username)); 166 | drawMessage("device: "+String(device), 1); 167 | drawMessage("id: "+String(uniqueid), 2); 168 | } 169 | 170 | drawMessage("packet length: "+String(packetSize), 3); 171 | drawMessage("RSSI: "+String(LoRa.packetRssi())+" SNR:"+String(LoRa.packetSnr()), 4); 172 | displayMessage(); 173 | 174 | delay(50); // delay before turning LED off 175 | digitalWrite(25, LOW); 176 | receivedTimestamp = millis(); 177 | } 178 | 179 | // show the message on the screen for 5 seconds 180 | if(receivedTimestamp != 0 && millis() > receivedTimestamp + 5000) { 181 | showWaitingMessage(); 182 | receivedTimestamp = 0; 183 | Serial.println("Resetting display"); 184 | } 185 | } 186 | --------------------------------------------------------------------------------