├── DHT end node ├── DHT-node.png ├── RFM_DHT_node_20.ino ├── RFM_DHT_node_21.ino ├── RFM_DHT_node_22.ino ├── Readme.txt └── Thumbs.db ├── DIG end node ├── DIG-node.png ├── DIG_node_relay.PNG ├── RFM_DIG_node_22.ino ├── Readme.txt └── Thumbs.db ├── Gateway_2.1 ├── MQTT_gateway_schema.jpg ├── RFM_MQTT_GW_21.ino ├── RFM_MQTT_gateway_description_V21.pdf ├── Readme.txt └── Thumbs.db ├── Gateway_2.2 ├── RFM_MQTT_GW_22.ino └── Readme.txt ├── Gateway_2.3 ├── MQTT_gateway_schema.jpg ├── RFM_MQTT_GW_23.ino ├── RFM_MQTT_gateway_description_V23.pdf └── Readme.txt ├── Gateway_2.4 ├── MQTT-GTW.png ├── RFM_MQTT_GW_24.ino ├── RFM_MQTT_gateway_description_V23.pdf ├── Readme.txt └── Thumbs.db ├── Gateway_2.5 ├── MQTT-GTW.png ├── RFM_MQTT_GW_25.ino ├── RFM_MQTT_gateway_description_V23.pdf ├── Readme.txt └── Thumbs.db ├── LCD end node ├── RFM_LCD_node_10.ino ├── RFM_LCD_node_20.ino ├── RFM_LCD_node_21.ino └── Readme.txt ├── LICENSE ├── Openhab Example ├── RFM_DHT_node_22_OH.ino ├── RFM_DIG_node_22_OH.ino ├── Readme.txt ├── base.items ├── base.rules └── base.sitemap ├── README.md ├── RFID end node ├── RFM_RFID_node_10.ino ├── RFM_RFID_node_20.ino └── readme.txt ├── Relay end node ├── Device │ └── device.h ├── README.md └── relay.ino ├── Remote Control node ├── RFM_RC_node_10.ino ├── RFM_RC_node_20.ino └── readme.txt ├── Version_1 Obsolete ├── Gateway │ ├── MQTT_gateway_schematic.jpg │ └── RFM_MQTT_GW_19.ino ├── Node │ ├── RFM_DHT_NODE_17.ino │ └── RFM_Node_schematic.jpg └── RFM_MQTT_gateway_description.pdf └── Version_2 Obsolete ├── RFM_DHT_node_20.ino ├── RFM_MQTT_GW_20.ino └── RFM_MQTT_gateway_description_V2.pdf /DHT end node/DHT-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/DHT end node/DHT-node.png -------------------------------------------------------------------------------- /DHT end node/RFM_DHT_node_21.ino: -------------------------------------------------------------------------------- 1 | // RFM69 DHT node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will: 4 | // - send sensor data periodically and on-demand 5 | // - receive commands from the gateway to control actuators 6 | // - receive commands from the gateway to change settings 7 | // 8 | // Several nodes can operate within a single network; each have a unique node ID. 9 | // On startup the node operates with default values, set on compilation. 10 | // 11 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 12 | // 13 | // A DHT-11 is used for temperature & humidity measurements, other sensors and outputs can be added easily. 14 | // 15 | // Message format is: nodeID/deviceID/command/integer/float/string 16 | // 17 | // Depending on the type of data (integer, float or string) one of the payload variables is used 18 | // Command = 0 means write a value in the node, cmd = 1 means read a value 19 | // 20 | // Current defined devices are: 21 | // 22 | // 0 uptime: read uptime node in minutes 23 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 24 | // 2 RSSI: read radio signal strength 25 | // 3 Version: read version node software 26 | // 4 voltage: read battery level 27 | // 5 ACK: read/set acknowledge message after a 'set' request 28 | // 6 toggle: read/set toggle function on button press 29 | // 7 timer: read/set activation timer after button press in seconds, 0 means no timer 30 | // 31 | // 16 actuator: read/set LED or relay output 32 | // 40 Button: tx only: message sent when button pressed 33 | // 48 temperature: read temperature 34 | // 49 humidity: read humidity 35 | // 90 error: tx only: error message if no wireless connection (generated by gateway) 36 | // 92 error: tx only: device not supported 37 | // 99 wakeup: tx only: first message sent on node startup 38 | // 39 | // The button can be set to: 40 | // - generate a message on each press (limited to one per 10 seconds) and/or 41 | // - toggle the output ACT1 (local node function) or 42 | // - activate the output for a fixed time period (local node function) 43 | // 44 | // A debug mode is included which outputs messages on the serial output 45 | // 46 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 47 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 48 | // 49 | // version 1.7 by Computourist@gmail.com december 2014 50 | // version 2.0 increased payload size; implemented node uptime; standard device type convention; error handling . 51 | // version 2.1 removed device 8; changed handling of device 40; compatible with gateway V2.2 ; march 2015 52 | 53 | #include 54 | #include 55 | #include 56 | 57 | // 58 | // CONFIGURATION PARAMETERS 59 | // 60 | #define NODEID 2 // unique node ID within the closed network 61 | #define GATEWAYID 1 // node ID of the Gateway is always 1 62 | #define NETWORKID 100 // network ID of the network 63 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 64 | //#define DEBUG // uncomment for debugging 65 | #define VERSION "DHT V2.1" // this value can be queried as device 3 66 | 67 | // Wireless settings Match frequency to the hardware version of the radio 68 | 69 | //#define FREQUENCY RF69_433MHZ 70 | #define FREQUENCY RF69_868MHZ 71 | //#define FREQUENCY RF69_915MHZ 72 | 73 | #define IS_RFM69HW // uncomment only for RFM69HW! 74 | #define ACK_TIME 50 // max # of ms to wait for an ack 75 | 76 | // DHT 11 / sensor setting 77 | #define DHTPIN 4 // DHT data connection 78 | #define DHTTYPE DHT11 // type of sensor 79 | #define ACT1 9 // Actuator pin (LED or relay) 80 | #define BTN 8 // Button pin 81 | #define SERIAL_BAUD 115200 82 | #define HOLDOFF 2000 // blocking period between button messages 83 | 84 | // 85 | // STARTUP DEFAULTS 86 | // 87 | long TXinterval = 20; // periodic transmission interval in seconds 88 | long TIMinterval = 20; // timer interval in seconds 89 | bool ackButton = false; // flag for message on button press 90 | bool toggleOnButton = true; // toggle output on button press 91 | 92 | // 93 | // VARIABLES 94 | // 95 | long lastPeriod = -1; // timestamp last transmission 96 | long lastBtnPress = -1; // timestamp last buttonpress 97 | long lastMinute = -1; // timestamp last minute 98 | long upTime = 0; // uptime in minutes 99 | float hum, temp; // humidity, temperature 100 | int ACT1State; // status ACT1 output 101 | int signalStrength; // radio signal strength 102 | bool setAck = false; // send ACK message on 'SET' request 103 | bool send0, send1, send2, send3, send4; 104 | bool send5, send6, send7; 105 | bool send16, send40, send48, send49, send92; // message triggers 106 | bool promiscuousMode = false; // only listen to nodes within the closed network 107 | bool curState = true; // current button state 108 | bool lastState = true; // last button state 109 | bool wakeUp = true; // wakeup flag 110 | bool timerOnButton = false; // timer output on button press 111 | bool msgBlock = false; // flag to hold button messages to prevent overload 112 | 113 | 114 | 115 | typedef struct { // Radio packet format 116 | int nodeID; // node identifier 117 | int devID; // device identifier 118 | int cmd; // read or write 119 | long intVal; // integer payload 120 | float fltVal; // floating payload 121 | char payLoad[32]; // string payload 122 | } Message; 123 | 124 | Message mes; 125 | 126 | DHT dht(DHTPIN, DHTTYPE, 3); // initialise temp/humidity sensor for 3.3 Volt arduino 127 | RFM69 radio; 128 | 129 | // 130 | //===================== SETUP ======================================== 131 | // 132 | void setup() { 133 | #ifdef DEBUG 134 | Serial.begin(SERIAL_BAUD); 135 | #endif 136 | pinMode(ACT1, OUTPUT); // set actuator 1 137 | ACT1State = 0; 138 | digitalWrite(ACT1, ACT1State); 139 | dht.begin(); // initialise temp/hum sensor 140 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 141 | #ifdef IS_RFM69HW 142 | radio.setHighPower(); // only for RFM69HW! 143 | #endif 144 | radio.encrypt(ENCRYPTKEY); // set radio encryption 145 | radio.promiscuous(promiscuousMode); // only listen to closed network 146 | wakeUp = true; // send wakeup message 147 | 148 | #ifdef DEBUG 149 | Serial.print("Node Software Version "); 150 | Serial.println(VERSION); 151 | Serial.print("\nTransmitting at "); 152 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 153 | Serial.println(" Mhz..."); 154 | #endif 155 | } // end setup 156 | 157 | // 158 | // 159 | //==================== MAIN ======================================== 160 | // 161 | void loop() { 162 | // RECEIVE radio input 163 | // 164 | if (receiveData()) parseCmd(); // receive and parse any radio input 165 | 166 | // DETECT INPUT CHANGE 167 | // 168 | curState = digitalRead(BTN); 169 | msgBlock = ((millis() - lastBtnPress) < HOLDOFF); // hold-off time for additional button messages 170 | if (!msgBlock && (curState != lastState)) { // input changed ? 171 | delay(5); 172 | lastBtnPress = millis(); // take timestamp 173 | send40 = true; // set button message flag 174 | if (curState == LOW) { 175 | if (toggleOnButton) { // button in toggle state ? 176 | ACT1State = !ACT1State; // toggle output 177 | digitalWrite(ACT1, ACT1State); 178 | } else 179 | if (TIMinterval > 0 && !timerOnButton) { // button in timer state ? 180 | timerOnButton = true; // start timer interval 181 | ACT1State = HIGH; // switch on ACT1 182 | digitalWrite(ACT1, ACT1State); 183 | }} 184 | lastState = curState; 185 | } 186 | 187 | // TIMER CHECK 188 | // 189 | 190 | if (TIMinterval > 0 && timerOnButton) // =0 means no timer 191 | { 192 | if ( millis() - lastBtnPress > TIMinterval*1000) { // timer expired ? 193 | timerOnButton = false; // then end timer interval 194 | ACT1State = LOW; // and switch off Actuator 195 | digitalWrite(ACT1, ACT1State); 196 | } 197 | } 198 | 199 | // UPTIME 200 | // 201 | 202 | if (lastMinute != (millis()/60000)) { // another minute passed ? 203 | lastMinute = millis()/60000; 204 | upTime++; 205 | } 206 | 207 | // PERIODIC TRANSMISSION 208 | // 209 | 210 | if (TXinterval > 0) 211 | { 212 | int currPeriod = millis()/(TXinterval*1000); 213 | if (currPeriod != lastPeriod) { // interval elapsed ? 214 | lastPeriod = currPeriod; 215 | 216 | // list of sensordata to be sent periodically.. 217 | // remove comment to include parameter in transmission 218 | 219 | // send1 = true; // send transmission interval 220 | // send2 = true; // signal strength 221 | // send4 = true; // voltage level 222 | // send16 = true; // actuator state 223 | send48 = true; // send temperature 224 | send49 = true; // send humidity 225 | } 226 | } 227 | 228 | // SEND RADIO PACKETS 229 | // 230 | 231 | sendMsg(); // send any radio messages 232 | 233 | } // end loop 234 | 235 | // 236 | // 237 | //===================== FUNCTIONS ========================================== 238 | 239 | // 240 | //======== RECEIVEDATA : receive data from gateway over radio 241 | // 242 | 243 | bool receiveData() { 244 | bool validPacket = false; 245 | if (radio.receiveDone()) // check for received packets 246 | { 247 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 248 | #ifdef DEBUG 249 | Serial.println("invalid message structure..") 250 | #endif 251 | ; 252 | else 253 | { 254 | mes = *(Message*)radio.DATA; 255 | validPacket = true; // YES, we have a packet ! 256 | signalStrength = radio.RSSI; 257 | #ifdef DEBUG 258 | Serial.print(mes.devID); 259 | Serial.print(", "); 260 | Serial.print(mes.cmd); 261 | Serial.print(", "); 262 | Serial.print(mes.intVal); 263 | Serial.print(", "); 264 | Serial.print(mes.fltVal); 265 | Serial.print(", RSSI= "); 266 | Serial.println(radio.RSSI); 267 | Serial.print("Node: "); 268 | Serial.println(mes.nodeID); 269 | #endif 270 | } 271 | } 272 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 273 | return validPacket; // return code indicates packet received 274 | } // end recieveData 275 | 276 | // 277 | // 278 | //============== PARSECMD: analyse messages and execute commands received from gateway 279 | // 280 | 281 | void parseCmd() { // parse messages received from the gateway 282 | send0 = false; // initialise all send triggers 283 | send1 = false; 284 | send2 = false; 285 | send3 = false; 286 | send4 = false; 287 | send5 = false; 288 | send6 = false; 289 | send7 = false; 290 | send16 = false; 291 | send40 = false; 292 | send48 = false; 293 | send49 = false; 294 | send92 = false; 295 | 296 | switch (mes.devID) // devID indicates device (sensor) type 297 | { 298 | case (0): // uptime 299 | if (mes.cmd == 1) send0 = true; 300 | break; 301 | case (1): // polling interval in seconds 302 | if (mes.cmd == 0) { // cmd == 0 means write a value 303 | TXinterval = mes.intVal; // change interval to radio packet value 304 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 305 | if (setAck) send1 = true; // send message if required 306 | #ifdef DEBUG 307 | Serial.print("Setting interval to "); 308 | Serial.print(TXinterval); 309 | Serial.println(" seconds"); 310 | #endif 311 | } 312 | else send1 = true; // cmd == 1 is a read request, so send polling interval 313 | break; 314 | case (2): // signal strength 315 | if (mes.cmd == 1) send2 = true; 316 | break; 317 | case (3): // software version 318 | if (mes.cmd == 1) send3 = true; 319 | break; 320 | case (4): // battery level 321 | if (mes.cmd == 1) send4 = true; 322 | break; 323 | case (5): // set ack status 324 | if (mes.cmd == 0) { 325 | if (mes.intVal == 0) setAck = false; 326 | if (mes.intVal == 1) setAck = true; 327 | if (setAck) send5 = true; // acknowledge message ? 328 | } 329 | else send5 = true; // read request means schedule a message 330 | break; 331 | case (6): // set toggle 332 | if (mes.cmd == 0) { 333 | if (mes.intVal == 0) toggleOnButton = false; 334 | if (mes.intVal == 1) toggleOnButton = true; 335 | if (setAck) send6 = true; // acknowledge message ? 336 | } 337 | else send6 = true; 338 | break; 339 | case (7): // timer interval in seconds 340 | if (mes.cmd == 0) { // cmd == 0 means write a value 341 | TIMinterval = mes.intVal; // change interval 342 | if (TIMinterval <5 && TIMinterval !=0) TIMinterval = 5; 343 | if (setAck) send7 = true; // acknowledge message ? 344 | } // cmd == 1 means read a value 345 | else send7 = true; // send timing interval 346 | break; 347 | case (16): // Actuator 1 348 | if (mes.cmd == 0) { // cmd == 0 means write 349 | if(mes.intVal == 0 || mes.intVal == 1) { 350 | ACT1State = mes.intVal; 351 | digitalWrite(ACT1, ACT1State); 352 | if (setAck) send16 = true; // acknowledge message ? 353 | #ifdef DEBUG 354 | Serial.print("Set LED to "); 355 | Serial.println(ACT1State); 356 | #endif 357 | }} 358 | else send16 = true; // cmd == 1 means read 359 | break; 360 | case (40): // binary input 361 | if (mes.cmd == 1) send40 = true; 362 | break; 363 | case (48): // temperature 364 | if (mes.cmd == 1) send48 = true; 365 | break; 366 | case (49): // humidity 367 | if (mes.cmd == 1) send49 = true; 368 | break; 369 | default: send92 = true; // no valid device parsed 370 | } 371 | } // end parseCmd 372 | 373 | // 374 | // 375 | //====================== SENDMSG: sends messages that are flagged for transmission 376 | // 377 | 378 | void sendMsg() { // prepares values to be transmitted 379 | bool tx = false; // transmission flag 380 | mes.nodeID=NODEID; 381 | mes.intVal = 0; 382 | mes.fltVal = 0; 383 | mes.cmd = 0; // '0' means no action needed in gateway 384 | int i; 385 | for ( i = 0; i < sizeof(VERSION); i++){ 386 | mes.payLoad[i] = VERSION[i]; } 387 | mes.payLoad[i] = '\0'; // software version in payload string 388 | 389 | if (wakeUp) { // send wakeUp call 390 | mes.devID = 99; 391 | wakeUp = false; // reset transmission flag for this message 392 | txRadio(); // transmit 393 | } 394 | if (send0) { 395 | mes.devID = 0; 396 | mes.intVal = upTime; // minutes uptime 397 | send0 = false; 398 | txRadio(); 399 | } 400 | if (send1) { // transmission interval 401 | mes.devID = 1; 402 | mes.intVal = TXinterval; // seconds (integer) 403 | send1 = false; 404 | txRadio(); 405 | } 406 | if (send2) { 407 | mes.devID = 2; 408 | mes.intVal = signalStrength; // signal strength (integer) 409 | send2 = false; 410 | txRadio(); 411 | } 412 | if (send3) { // node software version (string) 413 | mes.devID = 3; // already stored in payload string 414 | send3 = false; 415 | txRadio(); 416 | } 417 | if (send4) { // measure voltage.. 418 | mes.devID = 4; 419 | long result; // Read 1.1V reference against AVcc 420 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 421 | delay(2); // Wait for Vref to settle 422 | ADCSRA |= _BV(ADSC); // Convert 423 | while (bit_is_set(ADCSRA,ADSC)); 424 | result = ADCL; 425 | result |= ADCH<<8; 426 | result = 1126400L / result; // Back-calculate in mV 427 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 428 | txRadio(); 429 | send4 = false; 430 | } 431 | if (send5) { // Acknowledge on 'SET' 432 | mes.devID = 5; 433 | if (setAck) mes.intVal = 1; else mes.intVal = 0;// state (integer) 434 | send5 = false; 435 | txRadio(); 436 | } 437 | if (send6) { // Toggle on Buttonpress 438 | mes.devID = 6; 439 | if (toggleOnButton) mes.intVal = 1; // read state of toggle flag 440 | else mes.intVal = 0; // state (integer) 441 | send6 = false; 442 | txRadio(); 443 | } 444 | if (send7) { // timer interval 445 | mes.devID = 7; 446 | mes.intVal = TIMinterval; // seconds (integer) 447 | send7 = false; 448 | txRadio(); 449 | } 450 | if (send16) { // state of Actuator 1 451 | mes.devID = 16; 452 | mes.intVal = ACT1State; // state (integer) 453 | send16 = false; 454 | txRadio(); 455 | } 456 | if (send40) { // Binary input read 457 | mes.devID = 40; 458 | if (curState == LOW) mes.intVal = 1; // state (integer) 459 | send40 = false; 460 | txRadio(); 461 | } 462 | if (send48) { // Temperature 463 | mes.devID = 48; 464 | temp = dht.readTemperature(); 465 | mes.fltVal = temp; // Degrees Celcius (float) 466 | send48 = false; 467 | txRadio(); 468 | } 469 | if (send49) { // Humidity 470 | mes.devID = 49; 471 | hum = dht.readHumidity(); 472 | mes.fltVal = hum; // Percentage (float) 473 | send49 = false; 474 | txRadio(); 475 | } 476 | if (send92) { // error message invalid device 477 | mes.intVal = mes.devID; 478 | mes.devID = 92; 479 | send92 = false; 480 | txRadio(); 481 | } 482 | 483 | } 484 | // 485 | // 486 | //======================= TXRADIO 487 | // 488 | 489 | void txRadio() // Transmits the 'mes'-struct to the gateway 490 | { 491 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes))) 492 | #ifdef DEBUG 493 | {Serial.print(" message "); 494 | Serial.print(mes.devID); 495 | Serial.println(" sent...");} 496 | else Serial.println("No connection...") 497 | #endif 498 | ;} // end txRadio 499 | 500 | 501 | 502 | 503 | 504 | 505 | -------------------------------------------------------------------------------- /DHT end node/Readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-DHT Release 2.2 2 | by Computourist@gmail.com Oct 2015 3 | 4 | Made this node compatible to gateway 2.3: 5 | - made changes in function TXradio to handle retransmissions. 6 | - added device 9 to expose the number of retransmission 7 | 8 | RFM-MQTT-DHT Release 2.1 9 | 10 | changed the way binary inputs behave. 11 | A message is sent at every state change, ON or OFF depending on the state of the binary input. 12 | This end node will function with gateway V2.2. 13 | 14 | See description of Gateway 2.2 on how to configure binary inputs in openhab. 15 | 16 | 17 | 18 | RFM-MQTT-DHT Release 2.0 19 | 20 | by Computourist@gmail.com Feb 2015 21 | 22 | This node talks to the MQTT-Gateway and will: 23 | - send sensor data periodically and on-demand 24 | - receive commands from the gateway to control actuators 25 | - receive commands from the gateway to change settings 26 | 27 | Several nodes can operate within a single network; each have a unique node ID. 28 | On startup the node operates with default values, set on compilation. 29 | 30 | Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 31 | 32 | A DHT-11 is used for temperature & humidity measurements, other sensors and outputs can be added easily. 33 | 34 | Message format is: nodeID/deviceID/command/integer/float/string 35 | 36 | Depending on the type of data (integer, float or string) one of the payload variables is used 37 | Command = 0 means write a value in the node, cmd = 1 means read a value 38 | 39 | Current defined devices are: 40 | 41 | 0 uptime: read uptime node in minutes 42 | 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 43 | 2 RSSI: read radio signal strength 44 | 3 Version: read version node software 45 | 4 voltage: read battery level 46 | 5 ACK: read/set acknowledge message after a 'set' request 47 | 6 toggle: read/set toggle function on button press 48 | 7 timer: read/set activation timer after button press in seconds, 0 means no timer 49 | 50 | 16 actuator: read/set LED or relay output 51 | 40 Button: tx only: message sent when button pressed 52 | 48 temperature: read temperature 53 | 49 humidity: read humidity 54 | 90 error: tx only: error message if no wireless connection (generated by gateway) 55 | 92 error: tx only: device not supported 56 | 99 wakeup: tx only: first message sent on node startup 57 | 58 | The button can be set to: 59 | - generate a message on each press (limited to one per 10 seconds) and/or 60 | - toggle the output ACT1 (local node function) or 61 | - activate the output for a fixed time period (local node function) 62 | 63 | A debug mode is included which outputs messages on the serial output 64 | 65 | RFM69 Library by Felix Rusu - felix@lowpowerlab.com 66 | Get the RFM69 library at: https://github.com/LowPowerLab/ 67 | -------------------------------------------------------------------------------- /DHT end node/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/DHT end node/Thumbs.db -------------------------------------------------------------------------------- /DIG end node/DIG-node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/DIG end node/DIG-node.png -------------------------------------------------------------------------------- /DIG end node/DIG_node_relay.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/DIG end node/DIG_node_relay.PNG -------------------------------------------------------------------------------- /DIG end node/RFM_DIG_node_22.ino: -------------------------------------------------------------------------------- 1 | // RFM69 DIG node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will control a digital output (LED, Relay): 4 | // - toggle output and send status message on local button push 5 | // - receive commands from the gateway to control output 6 | // - periodically send status messages 7 | // - receive commands from the gateway to change settings 8 | // 9 | // Several nodes can operate within a single network; each have a unique node ID. 10 | // On startup the node operates with default values, set on compilation. 11 | // 12 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 13 | // 14 | // Sensors and outputs can be added easily. 15 | // 16 | // Message format is: nodeID/deviceID/command/integer/float/string 17 | // 18 | // Depending on the type of data (integer, float or string) one of the payload variables is used 19 | // Command = 0 means write a value in the node, cmd = 1 means read a value 20 | // 21 | // Current defined devices are: 22 | // 23 | // 0 uptime: read uptime node in minutes 24 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 25 | // 2 RSSI: read radio signal strength 26 | // 3 Version: read version node software 27 | // 4 voltage: read battery level 28 | // 5 ACK: read/set acknowledge message after a 'set' request 29 | // 6 toggle: read/set toggle function on button press 30 | // 7 timer: read/set activation timer after button press in seconds, 0 means no timer 31 | // 9 retry: read number of retransmissions needed in radiolink 32 | // 33 | // 16 actuator: read/set LED or relay output 34 | // 40 Button: tx only: message sent when button pressed 35 | // 90 error: tx only: error message if no wireless connection (generated by gateway) 36 | // 92 error: tx only: device not supported 37 | // 99 wakeup: tx only: first message sent on node startup 38 | // 39 | // The button can be set to: 40 | // - generate a message on each press (limited to one per 10 seconds) and/or 41 | // - toggle the output ACT1 (local node function) or 42 | // - activate the output for a fixed time period (local node function) 43 | // 44 | // A debug mode is included which outputs messages on the serial output 45 | // 46 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 47 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 48 | // 49 | // version 1.7 by Computourist@gmail.com december 2014 50 | // version 2.0 increased payload size; implemented node uptime; standard device type convention; error handling . 51 | // version 2.1 removed device 8; changed handling of device 40; compatible with gateway V2.2 ; march 2015 52 | // version 2.2 fixed bug in function TXradio that prevented retransmission of radio packets ; 53 | // implemented device 9 to show the number of retransmissions on the radio link; oct 2015 54 | 55 | #include 56 | #include 57 | 58 | 59 | // 60 | // CONFIGURATION PARAMETERS 61 | // 62 | #define NODEID 6 // unique node ID within the closed network 63 | #define GATEWAYID 1 // node ID of the Gateway is always 1 64 | #define NETWORKID 100 // network ID of the network 65 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 66 | #define DEBUG // uncomment for debugging 67 | #define VERSION "DIG V2.2" // this value can be queried as device 3 68 | 69 | // Wireless settings Match frequency to the hardware version of the radio 70 | 71 | //#define FREQUENCY RF69_433MHZ 72 | #define FREQUENCY RF69_868MHZ 73 | //#define FREQUENCY RF69_915MHZ 74 | 75 | #define IS_RFM69HW // uncomment only for RFM69HW! 76 | #define ACK_TIME 50 // max # of ms to wait for an ack 77 | 78 | // sensor setting 79 | 80 | #define ACT1 9 // Actuator pin (LED or relay) 81 | #define BTN 8 // Button pin 82 | #define SERIAL_BAUD 115200 83 | #define HOLDOFF 1000 // blocking period between button messages 84 | 85 | // 86 | // STARTUP DEFAULTS 87 | // 88 | long TXinterval = 120; // periodic transmission interval in seconds 89 | long TIMinterval = 20; // timer interval in seconds 90 | bool ackButton = false; // flag for message on button press 91 | bool toggleOnButton = true; // toggle output on button press 92 | 93 | // 94 | // VARIABLES 95 | // 96 | long lastPeriod = -1; // timestamp last transmission 97 | long lastBtnPress = -1; // timestamp last buttonpress 98 | long lastMinute = -1; // timestamp last minute 99 | long upTime = 0; // uptime in minutes 100 | int ACT1State; // status ACT1 output 101 | int signalStrength; // radio signal strength 102 | bool setAck = false; // send ACK message on 'SET' request 103 | bool send0, send1, send2, send3, send4; 104 | bool send5, send6, send7,send9; 105 | bool send16, send40, send92; // message triggers 106 | bool promiscuousMode = false; // only listen to nodes within the closed network 107 | bool curState = true; // current button state 108 | bool lastState = true; // last button state 109 | bool wakeUp = true; // wakeup flag 110 | bool timerOnButton = false; // timer output on button press 111 | bool msgBlock = false; // flag to hold button messages to prevent overload 112 | bool retx = true; // flag to signal retransmission 113 | int numtx; // number of retransmissions 114 | 115 | typedef struct { // Radio packet format 116 | int nodeID; // node identifier 117 | int devID; // device identifier 118 | int cmd; // read or write 119 | long intVal; // integer payload 120 | float fltVal; // floating payload 121 | char payLoad[32]; // string payload 122 | } Message; 123 | 124 | Message mes; 125 | 126 | 127 | RFM69 radio; 128 | 129 | // 130 | //===================== SETUP ======================================== 131 | // 132 | void setup() { 133 | #ifdef DEBUG 134 | Serial.begin(SERIAL_BAUD); 135 | #endif 136 | pinMode(ACT1, OUTPUT); // set actuator 1 137 | ACT1State = 0; 138 | digitalWrite(ACT1, ACT1State); 139 | 140 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 141 | #ifdef IS_RFM69HW 142 | radio.setHighPower(); // only for RFM69HW! 143 | #endif 144 | radio.encrypt(ENCRYPTKEY); // set radio encryption 145 | radio.promiscuous(promiscuousMode); // only listen to closed network 146 | wakeUp = true; // send wakeup message 147 | 148 | #ifdef DEBUG 149 | Serial.print("Node Software Version "); 150 | Serial.println(VERSION); 151 | Serial.print("\nTransmitting at "); 152 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 153 | Serial.println(" Mhz..."); 154 | #endif 155 | } // end setup 156 | 157 | // 158 | // 159 | //==================== MAIN ======================================== 160 | // 161 | void loop() { 162 | // RECEIVE radio input 163 | // 164 | if (receiveData()) parseCmd(); // receive and parse any radio input 165 | 166 | // DETECT INPUT CHANGE 167 | // 168 | curState = digitalRead(BTN); // Read button 169 | msgBlock = ((millis() - lastBtnPress) < HOLDOFF); // hold-off time for additional button messages 170 | if (!msgBlock && (curState != lastState)) { // input changed ? 171 | delay(5); 172 | lastBtnPress = millis(); // take timestamp 173 | // send40 = true; // set button message flag 174 | if (curState == LOW) { 175 | if (toggleOnButton) { // button in toggle state ? 176 | ACT1State = !ACT1State; // toggle output 177 | digitalWrite(ACT1, ACT1State); 178 | send16 = true; // send message on status change 179 | } else 180 | if (TIMinterval > 0 && !timerOnButton) { // button in timer state ? 181 | timerOnButton = true; // start timer interval 182 | ACT1State = HIGH; // switch on ACT1 183 | digitalWrite(ACT1, ACT1State); 184 | }} 185 | lastState = curState; 186 | } 187 | 188 | // TIMER CHECK 189 | // 190 | 191 | if (TIMinterval > 0 && timerOnButton) // =0 means no timer 192 | { 193 | if ( millis() - lastBtnPress > TIMinterval*1000) { // timer expired ? 194 | timerOnButton = false; // then end timer interval 195 | ACT1State = LOW; // and switch off Actuator 196 | digitalWrite(ACT1, ACT1State); 197 | } 198 | } 199 | 200 | // UPTIME 201 | // 202 | 203 | if (lastMinute != (millis()/60000)) { // another minute passed ? 204 | lastMinute = millis()/60000; 205 | upTime++; 206 | } 207 | 208 | // PERIODIC TRANSMISSION 209 | // 210 | 211 | if (TXinterval > 0) 212 | { 213 | int currPeriod = millis()/(TXinterval*1000); 214 | if (currPeriod != lastPeriod) { // interval elapsed ? 215 | lastPeriod = currPeriod; 216 | 217 | // list of sensordata to be sent periodically.. 218 | // remove comment to include parameter in transmission 219 | 220 | // send1 = true; // send transmission interval 221 | // send2 = true; // signal strength 222 | // send4 = true; // voltage level 223 | // send9 = true; // number of retransmissions 224 | send16 = true; // output state 225 | 226 | } 227 | } 228 | 229 | // SEND RADIO PACKETS 230 | // 231 | 232 | sendMsg(); // send any radio messages 233 | 234 | } // end loop 235 | 236 | // 237 | // 238 | //===================== FUNCTIONS ========================================== 239 | 240 | // 241 | //======== RECEIVEDATA : receive data from gateway over radio 242 | // 243 | 244 | bool receiveData() { 245 | bool validPacket = false; 246 | if (radio.receiveDone()) // check for received packets 247 | { 248 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 249 | #ifdef DEBUG 250 | Serial.println("invalid message structure..") 251 | #endif 252 | ; 253 | else 254 | { 255 | mes = *(Message*)radio.DATA; 256 | validPacket = true; // YES, we have a packet ! 257 | signalStrength = radio.RSSI; 258 | #ifdef DEBUG 259 | Serial.print(mes.devID); 260 | Serial.print(", "); 261 | Serial.print(mes.cmd); 262 | Serial.print(", "); 263 | Serial.print(mes.intVal); 264 | Serial.print(", "); 265 | Serial.print(mes.fltVal); 266 | Serial.print(", RSSI= "); 267 | Serial.println(radio.RSSI); 268 | Serial.print("Node: "); 269 | Serial.println(mes.nodeID); 270 | #endif 271 | } 272 | } 273 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 274 | return validPacket; // return code indicates packet received 275 | } // end recieveData 276 | 277 | // 278 | // 279 | //============== PARSECMD: analyse messages and execute commands received from gateway 280 | // 281 | 282 | void parseCmd() { // parse messages received from the gateway 283 | send0 = false; // initialise all send triggers 284 | send1 = false; 285 | send2 = false; 286 | send3 = false; 287 | send4 = false; 288 | send5 = false; 289 | send6 = false; 290 | send7 = false; 291 | send9 = false; 292 | send16 = false; 293 | send40 = false; 294 | 295 | send92 = false; 296 | 297 | switch (mes.devID) // devID indicates device (sensor) type 298 | { 299 | case (0): // uptime 300 | if (mes.cmd == 1) send0 = true; 301 | break; 302 | case (1): // polling interval in seconds 303 | if (mes.cmd == 0) { // cmd == 0 means write a value 304 | TXinterval = mes.intVal; // change interval to radio packet value 305 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 306 | if (setAck) send1 = true; // send message if required 307 | #ifdef DEBUG 308 | Serial.print("Setting interval to "); 309 | Serial.print(TXinterval); 310 | Serial.println(" seconds"); 311 | #endif 312 | } 313 | else send1 = true; // cmd == 1 is a read request, so send polling interval 314 | break; 315 | case (2): // signal strength 316 | if (mes.cmd == 1) send2 = true; 317 | break; 318 | case (3): // software version 319 | if (mes.cmd == 1) send3 = true; 320 | break; 321 | case (4): // battery level 322 | if (mes.cmd == 1) send4 = true; 323 | break; 324 | case (5): // set ack status 325 | if (mes.cmd == 0) { 326 | if (mes.intVal == 0) setAck = false; 327 | if (mes.intVal == 1) setAck = true; 328 | if (setAck) send5 = true; // acknowledge message ? 329 | } 330 | else send5 = true; // read request means schedule a message 331 | break; 332 | case (6): // set toggle 333 | if (mes.cmd == 0) { 334 | if (mes.intVal == 0) toggleOnButton = false; 335 | if (mes.intVal == 1) toggleOnButton = true; 336 | if (setAck) send6 = true; // acknowledge message ? 337 | } 338 | else send6 = true; 339 | break; 340 | case (7): // timer interval in seconds 341 | if (mes.cmd == 0) { // cmd == 0 means write a value 342 | TIMinterval = mes.intVal; // change interval 343 | if (TIMinterval <5 && TIMinterval !=0) TIMinterval = 5; 344 | if (setAck) send7 = true; // acknowledge message ? 345 | } // cmd == 1 means read a value 346 | else send7 = true; // send timing interval 347 | break; 348 | case (9): // retransmissions 349 | if (mes.cmd == 1) send9 = true; 350 | break; 351 | case (16): // output 352 | if (mes.cmd == 0) { // cmd == 0 means write 353 | if(mes.intVal == 0 || mes.intVal == 1) { 354 | ACT1State = mes.intVal; 355 | digitalWrite(ACT1, ACT1State); 356 | if (setAck) send16 = true; // acknowledge message ? 357 | #ifdef DEBUG 358 | Serial.print("Set LED to "); 359 | Serial.println(ACT1State); 360 | #endif 361 | }} 362 | else send16 = true; // cmd == 1 means read 363 | break; 364 | case (40): // binary input 365 | if (mes.cmd == 1) send40 = true; 366 | break; 367 | 368 | default: send92 = true; // no valid device parsed 369 | } 370 | } // end parseCmd 371 | 372 | // 373 | // 374 | //====================== SENDMSG: sends messages that are flagged for transmission 375 | // 376 | 377 | void sendMsg() { // prepares values to be transmitted 378 | bool tx = false; // transmission flag 379 | mes.nodeID=NODEID; 380 | mes.intVal = 0; 381 | mes.fltVal = 0; 382 | mes.cmd = 0; // '0' means no action needed in gateway 383 | int i; 384 | for ( i = 0; i < sizeof(VERSION); i++){ 385 | mes.payLoad[i] = VERSION[i]; } 386 | mes.payLoad[i] = '\0'; // software version in payload string 387 | 388 | if (wakeUp) { // send wakeUp call 389 | mes.devID = 99; 390 | wakeUp = false; // reset transmission flag for this message 391 | txRadio(); // transmit 392 | } 393 | if (send0) { 394 | mes.devID = 0; 395 | mes.intVal = upTime; // minutes uptime 396 | send0 = false; 397 | txRadio(); 398 | } 399 | if (send1) { // transmission interval 400 | mes.devID = 1; 401 | mes.intVal = TXinterval; // seconds (integer) 402 | send1 = false; 403 | txRadio(); 404 | } 405 | if (send2) { 406 | mes.devID = 2; 407 | mes.intVal = signalStrength; // signal strength (integer) 408 | send2 = false; 409 | txRadio(); 410 | } 411 | if (send3) { // node software version (string) 412 | mes.devID = 3; // already stored in payload string 413 | send3 = false; 414 | txRadio(); 415 | } 416 | if (send4) { // measure voltage.. 417 | mes.devID = 4; 418 | long result; // Read 1.1V reference against AVcc 419 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 420 | delay(2); // Wait for Vref to settle 421 | ADCSRA |= _BV(ADSC); // Convert 422 | while (bit_is_set(ADCSRA,ADSC)); 423 | result = ADCL; 424 | result |= ADCH<<8; 425 | result = 1126400L / result; // Back-calculate in mV 426 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 427 | txRadio(); 428 | send4 = false; 429 | } 430 | if (send5) { // Acknowledge on 'SET' 431 | mes.devID = 5; 432 | if (setAck) mes.intVal = 1; else mes.intVal = 0; // state (integer) 433 | send5 = false; 434 | txRadio(); 435 | } 436 | if (send6) { // Toggle on Buttonpress 437 | mes.devID = 6; 438 | if (toggleOnButton) mes.intVal = 1; // read state of toggle flag 439 | else mes.intVal = 0; // state (integer) 440 | send6 = false; 441 | txRadio(); 442 | } 443 | if (send7) { // timer interval 444 | mes.devID = 7; 445 | mes.intVal = TIMinterval; // seconds (integer) 446 | send7 = false; 447 | txRadio(); 448 | } 449 | if (send9) { // number of retransmissions 450 | mes.devID = 9; 451 | mes.intVal = numtx; // number (integer) 452 | send9 = false; 453 | txRadio(); 454 | } 455 | if (send16) { // state of Actuator 1 456 | mes.devID = 16; 457 | mes.intVal = ACT1State; // state (integer) 458 | send16 = false; 459 | txRadio(); 460 | } 461 | if (send40) { // Binary input read 462 | mes.devID = 40; 463 | if (curState == LOW) mes.intVal = 1; // state (integer) 464 | send40 = false; 465 | txRadio(); 466 | } 467 | if (send92) { // error message invalid device 468 | mes.intVal = mes.devID; 469 | mes.devID = 92; 470 | send92 = false; 471 | txRadio(); 472 | } 473 | 474 | } 475 | // 476 | // 477 | //======================= TXRADIO 478 | // 479 | 480 | void txRadio() // Transmits the 'mes'-struct to the gateway 481 | { 482 | retx = true; 483 | int i = 0; 484 | 485 | while (retx && i<6) { 486 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes),5)) { 487 | retx = false; 488 | #ifdef DEBUG 489 | Serial.print(" message "); 490 | Serial.print(mes.devID); 491 | Serial.println(" sent..."); 492 | #endif 493 | } else delay(500); 494 | i++; 495 | } 496 | numtx = i; // store number of retransmissions needed 497 | #ifdef DEBUG 498 | if (retx) Serial.println("No connection...") 499 | #endif 500 | ;} // end txRadio 501 | 502 | 503 | 504 | 505 | 506 | 507 | -------------------------------------------------------------------------------- /DIG end node/Readme.txt: -------------------------------------------------------------------------------- 1 | 2 | RFM-MQTT-DIG Release 2.2 3 | 4 | by Computourist@gmail.com October 2015 5 | 6 | The DIG end node is basically a lean DHT node. It's only function is to control a digital output (Relay, LED). 7 | It has: 8 | - an output to control the load (set at pin 9) 9 | - an input to connect a pushbutton (at pin 8 with a pull-up resistor of 10 K) 10 | 11 | It has the same schematic as the DHT-node, just leave out the DHT module. 12 | 13 | The push button can be used to locally toggle the output. On every state change a message is generated. 14 | 15 | In this node a bug in the retransmission mechanism is fixed. The number of transmissions needed can be read thru device 9. 16 | 17 | Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 18 | 19 | 20 | Current defined devices are: 21 | 22 | 0 uptime: read uptime node in minutes 23 | 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 24 | 2 RSSI: read radio signal strength 25 | 3 Version: read version node software 26 | 4 voltage: read battery level 27 | 5 ACK: read/set acknowledge message after a 'set' request 28 | 6 toggle: read/set toggle function on button press 29 | 7 timer: read/set activation timer after button press in seconds, 0 means no timer 30 | 9 numTX: read the number of retransmissions needed 31 | 32 | 16 actuator: read/set LED or relay output 33 | 40 Button: tx only: message sent when button pressed 34 | 35 | 90 error: tx only: error message if no wireless connection (generated by gateway) 36 | 92 error: tx only: device not supported 37 | 99 wakeup: tx only: first message sent on node startup 38 | 39 | 40 | A debug mode is included which outputs messages on the serial output 41 | 42 | RFM69 Library by Felix Rusu - felix@lowpowerlab.com 43 | Get the RFM69 library at: https://github.com/LowPowerLab/ 44 | -------------------------------------------------------------------------------- /DIG end node/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/DIG end node/Thumbs.db -------------------------------------------------------------------------------- /Gateway_2.1/MQTT_gateway_schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.1/MQTT_gateway_schema.jpg -------------------------------------------------------------------------------- /Gateway_2.1/RFM_MQTT_gateway_description_V21.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.1/RFM_MQTT_gateway_description_V21.pdf -------------------------------------------------------------------------------- /Gateway_2.1/Readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-Gateway Release 2.1 2 | 3 | by Computourist@gmail.com Feb 2015 4 | 5 | - implemented device 72 for transparant string transmission 6 | - implemented uniform handling for binary input devices 7 | - minor bugfixing 8 | -------------------------------------------------------------------------------- /Gateway_2.1/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.1/Thumbs.db -------------------------------------------------------------------------------- /Gateway_2.2/Readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-Gateway Release 2.2 2 | 3 | by Computourist@gmail.com March 2015 4 | 5 | - changed handling of binary inputs. 6 | In order to be more compatible with the way openhab handles messages the binary inputs were changed. 7 | On every state transition a message is generated with "ON" or "OFF" in the message block, 8 | depending on the actual state of the input. 9 | 10 | in Openhab a "contact" item needs to be declared: 11 | 12 | Contact window "Status [%s]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev40:state:OPEN:ON],<[mosquitto:home/rfm_gw/nb/node02/dev40:state:CLOSED:OFF]"} 13 | 14 | in the openhab Sitemap the following frame should be included to show the state of the binary input: 15 | 16 | Frame label="Contacts" { Text item=window } 17 | 18 | - fixed RSSI reporting 19 | Originally the end node reported on signal strength. 20 | As long as no packets were being received from the gateway its value would remain constant. 21 | Reporting RSSI by means of the end-node transmission interval would therefor always report the same value. 22 | RSSI is now calculated by the reception strength of packets received in the gateway. 23 | Every time a packet is received from the end node (whether in push- or pull mode) a new and actual value is reported. 24 | 25 | - partly removed DEBUG code 26 | Memory restrictions forced the removal of part of the debug code. 27 | Voltage reporting by entering 'v' on serial input was removed. 28 | 29 | Note that these changes should also be reflected in end nodes that have binary input: 30 | - LCD node from version 2.0 31 | - DHT node from version 2.1 32 | 33 | 34 | 35 | RFM-MQTT-Gateway Release 2.1 36 | 37 | by Computourist@gmail.com Feb 2015 38 | 39 | - implemented device 72 for transparant string transmission 40 | - implemented uniform handling for binary input devices 41 | - minor bugfixing 42 | -------------------------------------------------------------------------------- /Gateway_2.3/MQTT_gateway_schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.3/MQTT_gateway_schema.jpg -------------------------------------------------------------------------------- /Gateway_2.3/RFM_MQTT_gateway_description_V23.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.3/RFM_MQTT_gateway_description_V23.pdf -------------------------------------------------------------------------------- /Gateway_2.3/Readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-Gateway Release 2.3 2 | 3 | by Computourist@gmail.com October 2015 4 | 5 | - implemented system device 9: 6 | Device 9 gives the number of retransmissions needed on the radiolink to receive a packet. 7 | Normally this value is 1, but under difficult radio conditions this number could go up to 6. 8 | This version is compatible with end nodes that work with gateway 2.2. 9 | To use device 9 this function needs to be implemented on the end-node also. 10 | 11 | - removed option 's' in the DEBUG menu. 12 | This serial link command would toggle push interval. It was removed to free up memory. 13 | 14 | 15 | 16 | ___________________________________________________________________________________________________________ 17 | RFM-MQTT-Gateway Release 2.2 18 | 19 | by Computourist@gmail.com March 2015 20 | 21 | - changed handling of binary inputs. 22 | In order to be more compatible with the way openhab handles messages the binary inputs were changed. 23 | On every state transition a message is generated with "ON" or "OFF" in the message block, 24 | depending on the actual state of the input. 25 | 26 | in Openhab a "contact" item needs to be declared: 27 | 28 | Contact window "Status [%s]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev40:state:OPEN:ON],<[mosquitto:home/rfm_gw/nb/node02/dev40:state:CLOSED:OFF]"} 29 | 30 | in the openhab Sitemap the following frame should be included to show the state of the binary input: 31 | 32 | Frame label="Contacts" { Text item=window } 33 | 34 | - fixed RSSI reporting 35 | Originally the end node reported on signal strength. 36 | As long as no packets were being received from the gateway its value would remain constant. 37 | Reporting RSSI by means of the end-node transmission interval would therefor always report the same value. 38 | RSSI is now calculated by the reception strength of packets received in the gateway. 39 | Every time a packet is received from the end node (whether in push- or pull mode) a new and actual value is reported. 40 | 41 | - partly removed DEBUG code 42 | Memory restrictions forced the removal of part of the debug code. 43 | Voltage reporting by entering 'v' on serial input was removed. 44 | 45 | Note that these changes should also be reflected in end nodes that have binary input: 46 | - LCD node from version 2.0 47 | - DHT node from version 2.1 48 | 49 | 50 | ___________________________________________________________________________________________________________ 51 | RFM-MQTT-Gateway Release 2.1 52 | 53 | by Computourist@gmail.com Feb 2015 54 | 55 | - implemented device 72 for transparant string transmission 56 | - implemented uniform handling for binary input devices 57 | - minor bugfixing 58 | -------------------------------------------------------------------------------- /Gateway_2.4/MQTT-GTW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.4/MQTT-GTW.png -------------------------------------------------------------------------------- /Gateway_2.4/RFM_MQTT_gateway_description_V23.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.4/RFM_MQTT_gateway_description_V23.pdf -------------------------------------------------------------------------------- /Gateway_2.4/Readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-Gateway Release 2.4 2 | 3 | by Computourist@gmail.com January 2016 4 | 5 | - Syntax change 6 | The last release of Arduino IDE forces a function te be declared before it is used. A function prototype was used for mqtt_sub. 7 | 8 | - split the DEBUG options. 9 | To free up memory the DEBUG options were split in a radio and an MQTT part. Only one of them can be used. 10 | 11 | 12 | 13 | ___________________________________________________________________________________________________________ 14 | 15 | RFM-MQTT-Gateway Release 2.3 16 | 17 | by Computourist@gmail.com October 2015 18 | 19 | - implemented system device 9: 20 | Device 9 gives the number of retransmissions needed on the radiolink to receive a packet. 21 | Normally this value is 1, but under difficult radio conditions this number could go up to 6. 22 | This version is compatible with end nodes that work with gateway 2.2. 23 | To use device 9 this function needs to be implemented on the end-node also. 24 | 25 | - removed option 's' in the DEBUG menu. 26 | This serial link command would toggle push interval. It was removed to free up memory. 27 | 28 | 29 | 30 | ___________________________________________________________________________________________________________ 31 | RFM-MQTT-Gateway Release 2.2 32 | 33 | by Computourist@gmail.com March 2015 34 | 35 | - changed handling of binary inputs. 36 | In order to be more compatible with the way openhab handles messages the binary inputs were changed. 37 | On every state transition a message is generated with "ON" or "OFF" in the message block, 38 | depending on the actual state of the input. 39 | 40 | in Openhab a "contact" item needs to be declared: 41 | 42 | Contact window "Status [%s]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev40:state:OPEN:ON],<[mosquitto:home/rfm_gw/nb/node02/dev40:state:CLOSED:OFF]"} 43 | 44 | in the openhab Sitemap the following frame should be included to show the state of the binary input: 45 | 46 | Frame label="Contacts" { Text item=window } 47 | 48 | - fixed RSSI reporting 49 | Originally the end node reported on signal strength. 50 | As long as no packets were being received from the gateway its value would remain constant. 51 | Reporting RSSI by means of the end-node transmission interval would therefor always report the same value. 52 | RSSI is now calculated by the reception strength of packets received in the gateway. 53 | Every time a packet is received from the end node (whether in push- or pull mode) a new and actual value is reported. 54 | 55 | - partly removed DEBUG code 56 | Memory restrictions forced the removal of part of the debug code. 57 | Voltage reporting by entering 'v' on serial input was removed. 58 | 59 | Note that these changes should also be reflected in end nodes that have binary input: 60 | - LCD node from version 2.0 61 | - DHT node from version 2.1 62 | 63 | 64 | ___________________________________________________________________________________________________________ 65 | RFM-MQTT-Gateway Release 2.1 66 | 67 | by Computourist@gmail.com Feb 2015 68 | 69 | - implemented device 72 for transparant string transmission 70 | - implemented uniform handling for binary input devices 71 | - minor bugfixing 72 | -------------------------------------------------------------------------------- /Gateway_2.4/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.4/Thumbs.db -------------------------------------------------------------------------------- /Gateway_2.5/MQTT-GTW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.5/MQTT-GTW.png -------------------------------------------------------------------------------- /Gateway_2.5/RFM_MQTT_gateway_description_V23.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.5/RFM_MQTT_gateway_description_V23.pdf -------------------------------------------------------------------------------- /Gateway_2.5/Readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-Gateway Release 2.5 2 | 3 | by Computourist@gmail.com January 2017 4 | 5 | - bugfix. 6 | As reported by rhyssman on the homeautomation.proboards.com forum: 7 | 8 | Integer values are limited to 16 bit in the MQTT messages, although they are transmitted as 32 bit over the radio network. 9 | 10 | ___________________________________________________________________________________________________________ 11 | 12 | 13 | RFM-MQTT-Gateway Release 2.4 14 | 15 | by Computourist@gmail.com January 2016 16 | 17 | - Syntax change 18 | The last release of Arduino IDE forces a function to be declared before it is used. A function prototype was used for mqtt_sub. 19 | 20 | - split the DEBUG options. 21 | To free up memory the DEBUG options were split in a radio and an MQTT part. Only one of them can be used at a time. 22 | 23 | 24 | 25 | ___________________________________________________________________________________________________________ 26 | 27 | RFM-MQTT-Gateway Release 2.3 28 | 29 | by Computourist@gmail.com October 2015 30 | 31 | - implemented system device 9: 32 | Device 9 gives the number of retransmissions needed on the radiolink to receive a packet. 33 | Normally this value is 1, but under difficult radio conditions this number could go up to 6. 34 | This version is compatible with end nodes that work with gateway 2.2. 35 | To use device 9 this function needs to be implemented on the end-node also. 36 | 37 | - removed option 's' in the DEBUG menu. 38 | This serial link command would toggle push interval. It was removed to free up memory. 39 | 40 | 41 | 42 | ___________________________________________________________________________________________________________ 43 | RFM-MQTT-Gateway Release 2.2 44 | 45 | by Computourist@gmail.com March 2015 46 | 47 | - changed handling of binary inputs. 48 | In order to be more compatible with the way openhab handles messages the binary inputs were changed. 49 | On every state transition a message is generated with "ON" or "OFF" in the message block, 50 | depending on the actual state of the input. 51 | 52 | in Openhab a "contact" item needs to be declared: 53 | 54 | Contact window "Status [%s]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev40:state:OPEN:ON],<[mosquitto:home/rfm_gw/nb/node02/dev40:state:CLOSED:OFF]"} 55 | 56 | in the openhab Sitemap the following frame should be included to show the state of the binary input: 57 | 58 | Frame label="Contacts" { Text item=window } 59 | 60 | - fixed RSSI reporting 61 | Originally the end node reported on signal strength. 62 | As long as no packets were being received from the gateway its value would remain constant. 63 | Reporting RSSI by means of the end-node transmission interval would therefor always report the same value. 64 | RSSI is now calculated by the reception strength of packets received in the gateway. 65 | Every time a packet is received from the end node (whether in push- or pull mode) a new and actual value is reported. 66 | 67 | - partly removed DEBUG code 68 | Memory restrictions forced the removal of part of the debug code. 69 | Voltage reporting by entering 'v' on serial input was removed. 70 | 71 | Note that these changes should also be reflected in end nodes that have binary input: 72 | - LCD node from version 2.0 73 | - DHT node from version 2.1 74 | 75 | 76 | ___________________________________________________________________________________________________________ 77 | RFM-MQTT-Gateway Release 2.1 78 | 79 | by Computourist@gmail.com Feb 2015 80 | 81 | - implemented device 72 for transparant string transmission 82 | - implemented uniform handling for binary input devices 83 | - minor bugfixing 84 | -------------------------------------------------------------------------------- /Gateway_2.5/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Gateway_2.5/Thumbs.db -------------------------------------------------------------------------------- /LCD end node/RFM_LCD_node_10.ino: -------------------------------------------------------------------------------- 1 | // RFM69 LCD node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will: 4 | // - send sensor data periodically and on-demand 5 | // - receive commands from the gateway to show on an LCD display 6 | // - receive commands from the gateway to change settings 7 | // 8 | // This node will work with gateway software from release 2.1 9 | // 10 | // Text messages should be targetted to device 72 and have the follwing format: 11 | // x:yyyyyyyyyyy 12 | // where x is the line number (0-1 or 0-3 depending on LCD device type) and yyyy is the text to be displayed. 13 | // 14 | // There are two buttons that generate button pressed codes (dev 40 & 41); 15 | // Once pressed a button is locked for "HOLDOFF" seconds to prevent flooding the network. 16 | // 17 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 18 | // The display is used at +5 Volts, no special interfacing needed. 19 | // 20 | // The RFM69 module is connected according to the diagram of the DTH-node. 21 | // Buttons are connected between GND and D0 and D1 with pullups resistors (10k) to 3.3 Volts. 22 | // Note that debug over serial port cannot be used simultaneously. (D0 and D1 are Tx and Rx) 23 | // 24 | // A 44780 type display is used, with the library as described in http://arduino.cc/en/Tutorial/LiquidCrystal 25 | // The LCD display is connected as follows: 26 | // - LCD RS pin to digital pin 3 27 | // - LCD Enable pin to digital pin 4 28 | // - LCD D4 pin to digital pin 5 29 | // - LCD D5 pin to digital pin 6 30 | // - LCD D6 pin to digital pin 7 31 | // - LCD D7 pin to digital pin 8 32 | // - LCD R/W pin to ground 33 | // - a potmeter (10K) between GND and +5 Volt for contrast adjustment, tap to pin 3 of the display. 34 | // 35 | // Defined node devices in this sketch are: 36 | // 37 | // 0 uptime: read uptime node in minutes 38 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 39 | // 2 RSSI: read radio signal strength 40 | // 3 Version: read version node software 41 | // 4 voltage: read battery level 42 | // 5 acknowledge: read/set acknowledge flag for text messages and SET actions 43 | // 40 BTN1: sends a message when pressed 44 | // 41 BTN2: sends a message when pressed 45 | // 72 display: display the text sent in the message payload 46 | // 90 error: tx only: error message if no wireless connection (generated by gateway) 47 | // 92 error: tx only: device not supported 48 | // 99 wakeup: tx only: first message sent on node startup 49 | // 50 | // 51 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 52 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 53 | // 54 | // version 1.0 by Computourist@gmail.com Feb 2015 55 | // 56 | 57 | #include 58 | #include 59 | #include 60 | 61 | // 62 | // CONFIGURATION PARAMETERS 63 | // 64 | #define NODEID 2 // unique node ID within the closed network 65 | #define GATEWAYID 1 // node ID of the Gateway is always 1 66 | #define NETWORKID 100 // network ID of the network 67 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 68 | //#define DEBUG // uncomment for debugging 69 | #define VERSION "LCD V1.0" // this value can be queried as device 3 70 | 71 | // Wireless settings Match frequency to the hardware version of the radio 72 | 73 | //#define FREQUENCY RF69_433MHZ 74 | #define FREQUENCY RF69_868MHZ 75 | //#define FREQUENCY RF69_915MHZ 76 | 77 | #define SERIAL_BAUD 115200 78 | #define IS_RFM69HW // uncomment only for RFM69HW! 79 | #define ACK_TIME 50 // max # of ms to wait for an ack 80 | 81 | #define BTN1 0 // buttons 82 | #define BTN2 1 83 | #define ROWS 4 // # of rows on the LCD 84 | #define COLS 20 // # of columns 85 | #define HOLDOFF 10000 // blocking period between button messages 86 | 87 | // 88 | // STARTUP DEFAULTS 89 | // 90 | long TXinterval = 20; // periodic transmission interval in seconds 91 | bool setAck = true; // flag for message on text message 92 | 93 | 94 | // 95 | // VARIABLES 96 | // 97 | long lastPeriod = -1; // timestamp last transmission 98 | long lastBtnPress = -1; // timestamp last buttonpress 99 | long lastMinute = -1; // timestamp last minute 100 | long upTime = 0; // uptime in minutes 101 | int signalStrength; // radio signal strength 102 | int line; // Display line 103 | int i,length; 104 | bool send0, send1, send2, send3, send4; 105 | bool send5, send40, send41; 106 | bool send72, send92; // message triggers 107 | bool promiscuousMode = false; // only listen to nodes within the closed network 108 | bool curState = true; // current button state 109 | bool lastState = true; // last button state 110 | bool wakeUp = true; // wakeup flag 111 | bool msgBlock = false; // flag to hold button messages to prevent overload 112 | char buff_mess[32]; 113 | 114 | 115 | typedef struct { // Radio packet format 116 | int nodeID; // node identifier 117 | int devID; // device identifier 118 | int cmd; // read or write 119 | long intVal; // integer payload 120 | float fltVal; // floating payload 121 | char payLoad[32]; // string payload 122 | } Message; 123 | 124 | Message mes; 125 | 126 | RFM69 radio; 127 | 128 | LiquidCrystal lcd(3, 4, 5, 6, 7, 8); // initialize LCD with the correct interface pins 129 | 130 | // 131 | //===================== SETUP ======================================== 132 | // 133 | void setup() { 134 | #ifdef DEBUG 135 | Serial.begin(SERIAL_BAUD); 136 | #endif 137 | 138 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 139 | #ifdef IS_RFM69HW 140 | radio.setHighPower(); // only for RFM69HW! 141 | #endif 142 | radio.encrypt(ENCRYPTKEY); // set radio encryption 143 | radio.promiscuous(promiscuousMode); // only listen to closed network 144 | wakeUp = true; // send wakeup message 145 | 146 | lcd.begin(COLS, ROWS); // set up the LCD's number of columns and rows: 147 | lcd.print("Startup "); // Print boot message to the LCD. 148 | lcd.print (VERSION); 149 | #ifdef DEBUG 150 | lcd.setCursor(0,2); 151 | lcd.print("DEBUG mode !!!"); 152 | Serial.print("Node Software Version "); 153 | Serial.println(VERSION); 154 | Serial.print("\nTransmitting at "); 155 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 156 | Serial.println(" Mhz..."); 157 | #endif 158 | } // end setup 159 | 160 | // 161 | // 162 | //==================== MAIN ======================================== 163 | // 164 | void loop() { 165 | // RECEIVE radio input 166 | // 167 | if (receiveData()) parseCmd(); // receive and parse any radio input 168 | 169 | // DETECT BUTTON PRESS 170 | // 171 | // This works NOT in debug mode; Tx and RX pins are in use !!!!! 172 | // 173 | #ifndef DEBUG 174 | msgBlock = (millis() - lastBtnPress < HOLDOFF); // hold-off time for additional button messages 175 | if (!msgBlock) { 176 | curState = digitalRead(BTN1); 177 | if (curState == LOW) { // button pressed ? 178 | lastBtnPress = millis(); // take timestamp 179 | send40 = true; // set button message flag 180 | } 181 | curState = digitalRead(BTN2); 182 | if (curState == LOW) { // button pressed ? 183 | lastBtnPress = millis(); // take timestamp 184 | send41 = true; // set button message flag 185 | } 186 | } 187 | #endif 188 | 189 | // UPTIME 190 | // 191 | 192 | if (lastMinute != (millis()/60000)) { // another minute passed ? 193 | lastMinute = millis()/60000; 194 | upTime++; 195 | } 196 | 197 | // PERIODIC TRANSMISSION 198 | // 199 | 200 | if (TXinterval > 0) 201 | { 202 | int currPeriod = millis()/(TXinterval*1000); 203 | if (currPeriod != lastPeriod) { // interval elapsed ? 204 | lastPeriod = currPeriod; 205 | 206 | // list of sensordata to be sent periodically.. 207 | // remove comment to include parameter in transmission 208 | 209 | // send0 = true; // send uptime 210 | send2 = true; // signal strength 211 | // send4 = true; // voltage level 212 | } 213 | } 214 | 215 | // SEND RADIO PACKETS 216 | // 217 | 218 | sendMsg(); // send any radio messages 219 | 220 | } // end loop 221 | 222 | // 223 | // 224 | //===================== FUNCTIONS ========================================== 225 | 226 | // 227 | //======== RECEIVEDATA : receive data from gateway over radio 228 | // 229 | 230 | bool receiveData() { 231 | bool validPacket = false; 232 | if (radio.receiveDone()) // check for received packets 233 | { 234 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 235 | #ifdef DEBUG 236 | Serial.println("invalid message structure..") 237 | #endif 238 | ; 239 | else 240 | { 241 | mes = *(Message*)radio.DATA; 242 | validPacket = true; // YES, we have a packet ! 243 | signalStrength = radio.RSSI; 244 | 245 | #ifdef DEBUG 246 | Serial.print(mes.devID); 247 | Serial.print(", "); 248 | Serial.print(mes.cmd); 249 | Serial.print(", "); 250 | Serial.print(mes.intVal); 251 | Serial.print(", "); 252 | Serial.print(mes.fltVal); 253 | Serial.print(", RSSI= "); 254 | Serial.println(radio.RSSI); 255 | Serial.print("Node: "); 256 | Serial.println(mes.nodeID); 257 | #endif 258 | } 259 | } 260 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 261 | return validPacket; // return code indicates packet received 262 | } // end recieveData 263 | 264 | // 265 | // 266 | //============== PARSECMD: analyse messages and execute commands received from gateway 267 | // 268 | 269 | void parseCmd() { // parse messages received from the gateway 270 | send0 = false; // initialise all send triggers 271 | send1 = false; 272 | send2 = false; 273 | send3 = false; 274 | send4 = false; 275 | send5 = false; 276 | send72 = false; 277 | send92 = false; 278 | 279 | switch (mes.devID) // devID indicates device (sensor) type 280 | { 281 | case (0): // uptime 282 | if (mes.cmd == 1) send0 = true; 283 | break; 284 | case (1): // polling interval in seconds 285 | if (mes.cmd == 0) { // cmd == 0 means write a value 286 | TXinterval = mes.intVal; // change interval to radio packet value 287 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 288 | if (setAck) send1 = true; // send message if required 289 | #ifdef DEBUG 290 | Serial.print("Setting interval to "); 291 | Serial.print(TXinterval); 292 | Serial.println(" seconds"); 293 | #endif 294 | } 295 | else send1 = true; // cmd == 1 is a read request, so send polling interval 296 | break; 297 | case (2): // signal strength 298 | if (mes.cmd == 1) send2 = true; 299 | break; 300 | case (3): // software version 301 | if (mes.cmd == 1) send3 = true; 302 | break; 303 | case (4): // battery level 304 | if (mes.cmd == 1) send4 = true; 305 | break; 306 | case (5): // set ack status 307 | if (mes.cmd == 0) { 308 | if (mes.intVal == 0) setAck = false; 309 | if (mes.intVal == 1) setAck = true; 310 | if (setAck) send5 = true; // acknowledge message ? 311 | } 312 | else send5 = true; // read request means schedule a message 313 | break; 314 | case (72): // string 315 | if (mes.cmd == 0) { // cmd == 0 means write a value 316 | 317 | String txtLine = String ((char*)mes.payLoad); // convert into string 318 | #ifdef DEBUG 319 | Serial.print("Received string: "); 320 | Serial.println(txtLine); 321 | Serial.print("Length: "); 322 | Serial.println(txtLine.length()); 323 | #endif 324 | 325 | if (txtLine.charAt(1)==58) { // is the second character a colon ? 326 | line = txtLine.charAt(0) - '0'; // get line number 327 | txtLine = txtLine.substring(2); // strip first 2 characters 328 | txtLine = txtLine.substring(0,COLS); // strip anything larger than linewidth 329 | if (line >= 0 && line < ROWS) { // valid line number ? 330 | lcd.setCursor(0,line); //set cursor on line 331 | lcd.print(txtLine); // print line 332 | if (txtLine.length() 58 | #include 59 | #include 60 | 61 | // 62 | // CONFIGURATION PARAMETERS 63 | // 64 | #define NODEID 3 // unique node ID within the closed network 65 | #define GATEWAYID 1 // node ID of the Gateway is always 1 66 | #define NETWORKID 100 // network ID of the network 67 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 68 | //#define DEBUG // uncomment for debugging 69 | #define VERSION "LCD V2.0" // this value can be queried as device 3 70 | 71 | // Wireless settings Match frequency to the hardware version of the radio 72 | 73 | //#define FREQUENCY RF69_433MHZ 74 | #define FREQUENCY RF69_868MHZ 75 | //#define FREQUENCY RF69_915MHZ 76 | 77 | #define SERIAL_BAUD 115200 78 | #define IS_RFM69HW // uncomment only for RFM69HW! 79 | #define ACK_TIME 50 // max # of ms to wait for an ack 80 | 81 | #define BTN1 0 // buttons 82 | #define BTN2 1 83 | #define ROWS 4 // # of rows on the LCD 84 | #define COLS 20 // # of columns 85 | #define HOLDOFF 2000 // blocking period between button messages 86 | 87 | // 88 | // STARTUP DEFAULTS 89 | // 90 | long TXinterval = 20; // periodic transmission interval in seconds 91 | bool setAck = true; // flag for message on text message 92 | 93 | 94 | // 95 | // VARIABLES 96 | // 97 | long lastPeriod = -1; // timestamp last transmission 98 | long lastBtnPress = -1; // timestamp last buttonpress 99 | long lastMinute = -1; // timestamp last minute 100 | long upTime = 0; // uptime in minutes 101 | int signalStrength; // radio signal strength 102 | int line; // Display line 103 | int i,length; 104 | bool send0, send1, send2, send3, send4; 105 | bool send5, send40, send41; 106 | bool send72, send92; // message triggers 107 | bool promiscuousMode = false; // only listen to nodes within the closed network 108 | bool curStateBtn1 = true; // current button state 109 | bool curStateBtn2 = true; // current button state 110 | bool btn1Last, btn2Last; // button state flags 111 | bool wakeUp = true; // wakeup flag 112 | bool msgBlock = false; // flag to hold button messages to prevent overload 113 | char buff_mess[32]; 114 | 115 | 116 | typedef struct { // Radio packet format 117 | int nodeID; // node identifier 118 | int devID; // device identifier 119 | int cmd; // read or write 120 | long intVal; // integer payload 121 | float fltVal; // floating payload 122 | char payLoad[32]; // string payload 123 | } Message; 124 | 125 | Message mes; 126 | 127 | RFM69 radio; 128 | 129 | LiquidCrystal lcd(3, 4, 5, 6, 7, 8); // initialize LCD with the correct interface pins 130 | 131 | // 132 | //===================== SETUP ======================================== 133 | // 134 | void setup() { 135 | #ifdef DEBUG 136 | Serial.begin(SERIAL_BAUD); 137 | #endif 138 | 139 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 140 | #ifdef IS_RFM69HW 141 | radio.setHighPower(); // only for RFM69HW! 142 | #endif 143 | radio.encrypt(ENCRYPTKEY); // set radio encryption 144 | radio.promiscuous(promiscuousMode); // only listen to closed network 145 | wakeUp = true; // send wakeup message 146 | 147 | lcd.begin(COLS, ROWS); // set up the LCD's number of columns and rows: 148 | lcd.print("Startup "); // Print boot message to the LCD. 149 | lcd.print (VERSION); 150 | #ifdef DEBUG 151 | lcd.setCursor(0,2); 152 | lcd.print("DEBUG mode !!!"); 153 | Serial.print("Node Software Version "); 154 | Serial.println(VERSION); 155 | Serial.print("\nTransmitting at "); 156 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 157 | Serial.println(" Mhz..."); 158 | #endif 159 | } // end setup 160 | 161 | // 162 | // 163 | //==================== MAIN ======================================== 164 | // 165 | void loop() { 166 | // RECEIVE radio input 167 | // 168 | if (receiveData()) parseCmd(); // receive and parse any radio input 169 | 170 | // DETECT BUTTON PRESS 171 | // 172 | // This works NOT in debug mode; Tx and RX pins are being used !!!!! 173 | // 174 | #ifndef DEBUG 175 | msgBlock = (millis() - lastBtnPress < HOLDOFF); // hold-off time for additional button messages 176 | if (!msgBlock) { 177 | curStateBtn1 = digitalRead(BTN1); 178 | if (curStateBtn1 != btn1Last) { // button pressed ? 179 | delay(5); 180 | lastBtnPress = millis(); // take timestamp 181 | send40 = true; // set button message flag 182 | } 183 | btn1Last = curStateBtn1; 184 | 185 | curStateBtn2 = digitalRead(BTN2); 186 | if (curStateBtn2 != btn2Last) { // button pressed ? 187 | delay(5); 188 | lastBtnPress = millis(); // take timestamp 189 | send41 = true; // set button message flag 190 | } 191 | btn2Last = curStateBtn2; 192 | } 193 | #endif 194 | 195 | // UPTIME 196 | // 197 | 198 | if (lastMinute != (millis()/60000)) { // another minute passed ? 199 | lastMinute = millis()/60000; 200 | upTime++; 201 | } 202 | 203 | // PERIODIC TRANSMISSION 204 | // 205 | 206 | if (TXinterval > 0) 207 | { 208 | int currPeriod = millis()/(TXinterval*1000); 209 | if (currPeriod != lastPeriod) { // interval elapsed ? 210 | lastPeriod = currPeriod; 211 | 212 | // list of sensordata to be sent periodically.. 213 | // remove comment to include parameter in transmission 214 | 215 | // send0 = true; // send uptime 216 | send2 = true; // signal strength 217 | // send4 = true; // voltage level 218 | } 219 | } 220 | 221 | // SEND RADIO PACKETS 222 | // 223 | 224 | sendMsg(); // send any radio messages 225 | 226 | } // end loop 227 | 228 | // 229 | // 230 | //===================== FUNCTIONS ========================================== 231 | 232 | // 233 | //======== RECEIVEDATA : receive data from gateway over radio 234 | // 235 | 236 | bool receiveData() { 237 | bool validPacket = false; 238 | if (radio.receiveDone()) // check for received packets 239 | { 240 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 241 | #ifdef DEBUG 242 | Serial.println("invalid message structure..") 243 | #endif 244 | ; 245 | else 246 | { 247 | mes = *(Message*)radio.DATA; 248 | validPacket = true; // YES, we have a packet ! 249 | signalStrength = radio.RSSI; 250 | #ifdef DEBUG 251 | Serial.print(mes.devID); 252 | Serial.print(", "); 253 | Serial.print(mes.cmd); 254 | Serial.print(", "); 255 | Serial.print(mes.intVal); 256 | Serial.print(", "); 257 | Serial.print(mes.fltVal); 258 | Serial.print(", RSSI= "); 259 | Serial.println(radio.RSSI); 260 | Serial.print("Node: "); 261 | Serial.println(mes.nodeID); 262 | // for (int i=0; i<32;i++) Serial.print(mes.payLoad[i]); 263 | Serial.println(); 264 | #endif 265 | } 266 | } 267 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 268 | return validPacket; // return code indicates packet received 269 | } // end recieveData 270 | 271 | // 272 | // 273 | //============== PARSECMD: analyse messages and execute commands received from gateway 274 | // 275 | 276 | void parseCmd() { // parse messages received from the gateway 277 | send0 = false; // initialise all send triggers 278 | send1 = false; 279 | send2 = false; 280 | send3 = false; 281 | send4 = false; 282 | send5 = false; 283 | send40 = false; 284 | send41 = false; 285 | send92 = false; 286 | 287 | switch (mes.devID) // devID indicates device (sensor) type 288 | { 289 | case (0): // uptime 290 | if (mes.cmd == 1) send0 = true; 291 | break; 292 | case (1): // polling interval in seconds 293 | if (mes.cmd == 0) { // cmd == 0 means write a value 294 | TXinterval = mes.intVal; // change interval to radio packet value 295 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 296 | if (setAck) send1 = true; // send message if required 297 | #ifdef DEBUG 298 | Serial.print("Setting interval to "); 299 | Serial.print(TXinterval); 300 | Serial.println(" seconds"); 301 | #endif 302 | } 303 | else send1 = true; // cmd == 1 is a read request, so send polling interval 304 | break; 305 | case (2): // signal strength 306 | if (mes.cmd == 1) send2 = true; 307 | break; 308 | case (3): // software version 309 | if (mes.cmd == 1) send3 = true; 310 | break; 311 | case (4): // battery level 312 | if (mes.cmd == 1) send4 = true; 313 | break; 314 | case (5): // set ack status 315 | if (mes.cmd == 0) { 316 | if (mes.intVal == 0) setAck = false; 317 | if (mes.intVal == 1) setAck = true; 318 | if (setAck) send5 = true; // acknowledge message ? 319 | } 320 | else send5 = true; // read request means schedule a message 321 | break; 322 | case (40): // Button 1 323 | if (mes.cmd == 1) send40 = true; 324 | break; 325 | case (41): // Button 2 326 | if (mes.cmd == 1) send41 = true; 327 | break; 328 | case (72): // string 329 | if (mes.cmd == 0) { // cmd == 0 means write a value 330 | 331 | String txtLine = String ((char*)mes.payLoad); 332 | #ifdef DEBUG 333 | Serial.print("Received string: "); 334 | Serial.println(txtLine); 335 | Serial.print("Length: "); 336 | Serial.println(txtLine.length()); 337 | #endif 338 | 339 | if (txtLine.charAt(1)==58) { 340 | line = txtLine.charAt(0) - '0'; 341 | txtLine = txtLine.substring(2); 342 | txtLine = txtLine.substring(0,COLS); 343 | if (line >= 0 && line < ROWS) { 344 | lcd.setCursor(0,line); 345 | lcd.print(txtLine); 346 | if (txtLine.length() 61 | #include 62 | #include 63 | 64 | // 65 | // CONFIGURATION PARAMETERS 66 | // 67 | #define NODEID 3 // unique node ID within the closed network 68 | #define GATEWAYID 1 // node ID of the Gateway is always 1 69 | #define NETWORKID 100 // network ID of the network 70 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 71 | //#define DEBUG // uncomment for debugging 72 | #define VERSION "LCD V2.1" // this value can be queried as device 3 73 | 74 | // Wireless settings Match frequency to the hardware version of the radio 75 | 76 | //#define FREQUENCY RF69_433MHZ 77 | #define FREQUENCY RF69_868MHZ 78 | //#define FREQUENCY RF69_915MHZ 79 | 80 | #define SERIAL_BAUD 115200 81 | #define IS_RFM69HW // uncomment only for RFM69HW! 82 | #define ACK_TIME 50 // max # of ms to wait for an ack 83 | 84 | #define BTN1 0 // buttons 85 | #define BTN2 1 86 | #define ROWS 4 // # of rows on the LCD 87 | #define COLS 20 // # of columns 88 | #define HOLDOFF 2000 // blocking period between button messages 89 | 90 | // 91 | // STARTUP DEFAULTS 92 | // 93 | long TXinterval = 20; // periodic transmission interval in seconds 94 | bool setAck = true; // flag for message on text message 95 | 96 | 97 | // 98 | // VARIABLES 99 | // 100 | long lastPeriod = -1; // timestamp last transmission 101 | long lastBtnPress = -1; // timestamp last buttonpress 102 | long lastMinute = -1; // timestamp last minute 103 | long upTime = 0; // uptime in minutes 104 | int signalStrength; // radio signal strength 105 | int line; // Display line 106 | int i,length; 107 | bool send0, send1, send2, send3, send4; 108 | bool send5, send9, send40, send41; 109 | bool send72, send92; // message triggers 110 | bool promiscuousMode = false; // only listen to nodes within the closed network 111 | bool curStateBtn1 = true; // current button state 112 | bool curStateBtn2 = true; // current button state 113 | bool btn1Last, btn2Last; // button state flags 114 | bool wakeUp = true; // wakeup flag 115 | bool msgBlock = false; // flag to hold button messages to prevent overload 116 | char buff_mess[32]; 117 | bool retx = true; // flag to signal retransmission 118 | int numtx; // number of retransmissions 119 | 120 | 121 | typedef struct { // Radio packet format 122 | int nodeID; // node identifier 123 | int devID; // device identifier 124 | int cmd; // read or write 125 | long intVal; // integer payload 126 | float fltVal; // floating payload 127 | char payLoad[32]; // string payload 128 | } Message; 129 | 130 | Message mes; 131 | 132 | RFM69 radio; 133 | 134 | LiquidCrystal lcd(3, 4, 5, 6, 7, 8); // initialize LCD with the correct interface pins 135 | 136 | // 137 | //===================== SETUP ======================================== 138 | // 139 | void setup() { 140 | #ifdef DEBUG 141 | Serial.begin(SERIAL_BAUD); 142 | #endif 143 | 144 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 145 | #ifdef IS_RFM69HW 146 | radio.setHighPower(); // only for RFM69HW! 147 | #endif 148 | radio.encrypt(ENCRYPTKEY); // set radio encryption 149 | radio.promiscuous(promiscuousMode); // only listen to closed network 150 | wakeUp = true; // send wakeup message 151 | 152 | lcd.begin(COLS, ROWS); // set up the LCD's number of columns and rows: 153 | lcd.print("Startup "); // Print boot message to the LCD. 154 | lcd.print (VERSION); 155 | #ifdef DEBUG 156 | lcd.setCursor(0,2); 157 | lcd.print("DEBUG mode !!!"); 158 | Serial.print("Node Software Version "); 159 | Serial.println(VERSION); 160 | Serial.print("\nTransmitting at "); 161 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 162 | Serial.println(" Mhz..."); 163 | #endif 164 | } // end setup 165 | 166 | // 167 | // 168 | //==================== MAIN ======================================== 169 | // 170 | void loop() { 171 | // RECEIVE radio input 172 | // 173 | if (receiveData()) parseCmd(); // receive and parse any radio input 174 | 175 | // DETECT BUTTON PRESS 176 | // 177 | // This works NOT in debug mode; Tx and RX pins are being used !!!!! 178 | // 179 | #ifndef DEBUG 180 | msgBlock = (millis() - lastBtnPress < HOLDOFF); // hold-off time for additional button messages 181 | if (!msgBlock) { 182 | curStateBtn1 = digitalRead(BTN1); 183 | if (curStateBtn1 != btn1Last) { // button pressed ? 184 | delay(5); 185 | lastBtnPress = millis(); // take timestamp 186 | send40 = true; // set button message flag 187 | } 188 | btn1Last = curStateBtn1; 189 | 190 | curStateBtn2 = digitalRead(BTN2); 191 | if (curStateBtn2 != btn2Last) { // button pressed ? 192 | delay(5); 193 | lastBtnPress = millis(); // take timestamp 194 | send41 = true; // set button message flag 195 | } 196 | btn2Last = curStateBtn2; 197 | } 198 | #endif 199 | 200 | // UPTIME 201 | // 202 | 203 | if (lastMinute != (millis()/60000)) { // another minute passed ? 204 | lastMinute = millis()/60000; 205 | upTime++; 206 | } 207 | 208 | // PERIODIC TRANSMISSION 209 | // 210 | 211 | if (TXinterval > 0) 212 | { 213 | int currPeriod = millis()/(TXinterval*1000); 214 | if (currPeriod != lastPeriod) { // interval elapsed ? 215 | lastPeriod = currPeriod; 216 | 217 | // list of sensordata to be sent periodically.. 218 | // remove comment to include parameter in transmission 219 | 220 | // send0 = true; // send uptime 221 | send2 = true; // signal strength 222 | // send4 = true; // voltage level 223 | // send9 = true; // number of retransmissions 224 | } 225 | } 226 | 227 | // SEND RADIO PACKETS 228 | // 229 | 230 | sendMsg(); // send any radio messages 231 | 232 | } // end loop 233 | 234 | // 235 | // 236 | //===================== FUNCTIONS ========================================== 237 | 238 | // 239 | //======== RECEIVEDATA : receive data from gateway over radio 240 | // 241 | 242 | bool receiveData() { 243 | bool validPacket = false; 244 | if (radio.receiveDone()) // check for received packets 245 | { 246 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 247 | #ifdef DEBUG 248 | Serial.println("invalid message structure..") 249 | #endif 250 | ; 251 | else 252 | { 253 | mes = *(Message*)radio.DATA; 254 | validPacket = true; // YES, we have a packet ! 255 | signalStrength = radio.RSSI; 256 | #ifdef DEBUG 257 | Serial.print(mes.devID); 258 | Serial.print(", "); 259 | Serial.print(mes.cmd); 260 | Serial.print(", "); 261 | Serial.print(mes.intVal); 262 | Serial.print(", "); 263 | Serial.print(mes.fltVal); 264 | Serial.print(", RSSI= "); 265 | Serial.println(radio.RSSI); 266 | Serial.print("Node: "); 267 | Serial.println(mes.nodeID); 268 | // for (int i=0; i<32;i++) Serial.print(mes.payLoad[i]); 269 | Serial.println(); 270 | #endif 271 | } 272 | } 273 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 274 | return validPacket; // return code indicates packet received 275 | } // end recieveData 276 | 277 | // 278 | // 279 | //============== PARSECMD: analyse messages and execute commands received from gateway 280 | // 281 | 282 | void parseCmd() { // parse messages received from the gateway 283 | send0 = false; // initialise all send triggers 284 | send1 = false; 285 | send2 = false; 286 | send3 = false; 287 | send4 = false; 288 | send5 = false; 289 | send9 = false; 290 | send40 = false; 291 | send41 = false; 292 | send92 = false; 293 | 294 | switch (mes.devID) // devID indicates device (sensor) type 295 | { 296 | case (0): // uptime 297 | if (mes.cmd == 1) send0 = true; 298 | break; 299 | case (1): // polling interval in seconds 300 | if (mes.cmd == 0) { // cmd == 0 means write a value 301 | TXinterval = mes.intVal; // change interval to radio packet value 302 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 303 | if (setAck) send1 = true; // send message if required 304 | #ifdef DEBUG 305 | Serial.print("Setting interval to "); 306 | Serial.print(TXinterval); 307 | Serial.println(" seconds"); 308 | #endif 309 | } 310 | else send1 = true; // cmd == 1 is a read request, so send polling interval 311 | break; 312 | case (2): // signal strength 313 | if (mes.cmd == 1) send2 = true; 314 | break; 315 | case (3): // software version 316 | if (mes.cmd == 1) send3 = true; 317 | break; 318 | case (4): // battery level 319 | if (mes.cmd == 1) send4 = true; 320 | break; 321 | case (5): // set ack status 322 | if (mes.cmd == 0) { 323 | if (mes.intVal == 0) setAck = false; 324 | if (mes.intVal == 1) setAck = true; 325 | if (setAck) send5 = true; // acknowledge message ? 326 | } 327 | else send5 = true; // read request means schedule a message 328 | break; 329 | case (9): // retransmissions 330 | if (mes.cmd == 1) send9 = true; 331 | break; 332 | case (40): // Button 1 333 | if (mes.cmd == 1) send40 = true; 334 | break; 335 | case (41): // Button 2 336 | if (mes.cmd == 1) send41 = true; 337 | break; 338 | case (72): // string 339 | if (mes.cmd == 0) { // cmd == 0 means write a value 340 | 341 | String txtLine = String ((char*)mes.payLoad); 342 | #ifdef DEBUG 343 | Serial.print("Received string: "); 344 | Serial.println(txtLine); 345 | Serial.print("Length: "); 346 | Serial.println(txtLine.length()); 347 | #endif 348 | 349 | if (txtLine.charAt(1)==58) { 350 | line = txtLine.charAt(0) - '0'; 351 | txtLine = txtLine.substring(2); 352 | txtLine = txtLine.substring(0,COLS); 353 | if (line >= 0 && line < ROWS) { 354 | lcd.setCursor(0,line); 355 | lcd.print(txtLine); 356 | if (txtLine.length() 41 | #include 42 | 43 | 44 | // 45 | // CONFIGURATION PARAMETERS 46 | // 47 | #define NODEID 6 // unique node ID within the closed network 48 | #define GATEWAYID 1 // node ID of the Gateway is always 1 49 | #define NETWORKID 100 // network ID of the network 50 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 51 | #define DEBUG // uncomment for debugging 52 | #define VERSION "DIG V2.2_OH" // this value can be queried as device 3 53 | 54 | // Wireless settings Match frequency to the hardware version of the radio 55 | 56 | //#define FREQUENCY RF69_433MHZ 57 | #define FREQUENCY RF69_868MHZ 58 | //#define FREQUENCY RF69_915MHZ 59 | 60 | #define IS_RFM69HW // uncomment only for RFM69HW! 61 | #define ACK_TIME 50 // max # of ms to wait for an ack 62 | 63 | // sensor setting 64 | 65 | #define ACT1 9 // Actuator pin (LED or relay) 66 | #define BTN 8 // Button pin 67 | #define SERIAL_BAUD 115200 68 | #define HOLDOFF 1000 // blocking period between button messages 69 | 70 | // 71 | // STARTUP DEFAULTS 72 | // 73 | long TXinterval = 120; // periodic transmission interval in seconds 74 | long TIMinterval = 20; // timer interval in seconds 75 | bool ackButton = false; // flag for message on button press 76 | bool toggleOnButton = true; // toggle output on button press 77 | 78 | // 79 | // VARIABLES 80 | // 81 | long lastPeriod = -1; // timestamp last transmission 82 | long lastBtnPress = -1; // timestamp last buttonpress 83 | long lastMinute = -1; // timestamp last minute 84 | long upTime = 0; // uptime in minutes 85 | int ACT1State; // status ACT1 output 86 | int signalStrength; // radio signal strength 87 | bool setAck = true; // send ACK message on 'SET' request 88 | bool send0, send1, send2, send3, send4; 89 | bool send5, send6, send7, send9; 90 | bool send16, send40, send92; // message triggers 91 | bool promiscuousMode = false; // only listen to nodes within the closed network 92 | bool curState = true; // current button state 93 | bool lastState = true; // last button state 94 | bool wakeUp = true; // wakeup flag 95 | bool timerOnButton = false; // timer output on button press 96 | bool msgBlock = false; // flag to hold button messages to prevent overload 97 | bool retx = true; // flag to signal retransmission 98 | int numtx; // number of retransmissions 99 | 100 | typedef struct { // Radio packet format 101 | int nodeID; // node identifier 102 | int devID; // device identifier 103 | int cmd; // read or write 104 | long intVal; // integer payload 105 | float fltVal; // floating payload 106 | char payLoad[32]; // string payload 107 | } Message; 108 | 109 | Message mes; 110 | 111 | 112 | RFM69 radio; 113 | 114 | // 115 | //===================== SETUP ======================================== 116 | // 117 | void setup() { 118 | #ifdef DEBUG 119 | Serial.begin(SERIAL_BAUD); 120 | #endif 121 | pinMode(ACT1, OUTPUT); // set actuator 1 122 | ACT1State = 0; 123 | digitalWrite(ACT1, ACT1State); 124 | 125 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 126 | #ifdef IS_RFM69HW 127 | radio.setHighPower(); // only for RFM69HW! 128 | #endif 129 | radio.encrypt(ENCRYPTKEY); // set radio encryption 130 | radio.promiscuous(promiscuousMode); // only listen to closed network 131 | wakeUp = true; // send wakeup message 132 | 133 | #ifdef DEBUG 134 | Serial.print("Node Software Version "); 135 | Serial.println(VERSION); 136 | Serial.print("\nTransmitting at "); 137 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 138 | Serial.println(" Mhz..."); 139 | #endif 140 | } // end setup 141 | 142 | // 143 | // 144 | //==================== MAIN ======================================== 145 | // 146 | void loop() { 147 | // RECEIVE radio input 148 | // 149 | if (receiveData()) parseCmd(); // receive and parse any radio input 150 | 151 | // DETECT INPUT CHANGE 152 | // 153 | curState = digitalRead(BTN); // Read button 154 | msgBlock = ((millis() - lastBtnPress) < HOLDOFF); // hold-off time for additional button messages 155 | if (!msgBlock && (curState != lastState)) { // input changed ? 156 | delay(5); 157 | lastBtnPress = millis(); // take timestamp 158 | // send40 = true; // set button message flag 159 | if (curState == LOW) { 160 | if (toggleOnButton) { // button in toggle state ? 161 | ACT1State = !ACT1State; // toggle output 162 | digitalWrite(ACT1, ACT1State); 163 | send16 = true; // send message on status change 164 | } else 165 | if (TIMinterval > 0 && !timerOnButton) { // button in timer state ? 166 | timerOnButton = true; // start timer interval 167 | ACT1State = HIGH; // switch on ACT1 168 | digitalWrite(ACT1, ACT1State); 169 | }} 170 | lastState = curState; 171 | } 172 | 173 | // TIMER CHECK 174 | // 175 | 176 | if (TIMinterval > 0 && timerOnButton) // =0 means no timer 177 | { 178 | if ( millis() - lastBtnPress > TIMinterval*1000) { // timer expired ? 179 | timerOnButton = false; // then end timer interval 180 | ACT1State = LOW; // and switch off Actuator 181 | digitalWrite(ACT1, ACT1State); 182 | } 183 | } 184 | 185 | // UPTIME 186 | // 187 | 188 | if (lastMinute != (millis()/60000)) { // another minute passed ? 189 | lastMinute = millis()/60000; 190 | upTime++; 191 | } 192 | 193 | // PERIODIC TRANSMISSION 194 | // 195 | 196 | if (TXinterval > 0) 197 | { 198 | int currPeriod = millis()/(TXinterval*1000); 199 | if (currPeriod != lastPeriod) { // interval elapsed ? 200 | lastPeriod = currPeriod; 201 | 202 | // list of sensordata to be sent periodically.. 203 | // remove comment to include parameter in transmission 204 | 205 | // send1 = true; // send transmission interval 206 | // send2 = true; // signal strength 207 | // send4 = true; // voltage level 208 | // send9 = true; // number of retransmissions 209 | send16 = true; // output state 210 | 211 | } 212 | } 213 | 214 | // SEND RADIO PACKETS 215 | // 216 | 217 | sendMsg(); // send any radio messages 218 | 219 | } // end loop 220 | 221 | // 222 | // 223 | //===================== FUNCTIONS ========================================== 224 | 225 | // 226 | //======== RECEIVEDATA : receive data from gateway over radio 227 | // 228 | 229 | bool receiveData() { 230 | bool validPacket = false; 231 | if (radio.receiveDone()) // check for received packets 232 | { 233 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 234 | #ifdef DEBUG 235 | Serial.println("invalid message structure..") 236 | #endif 237 | ; 238 | else 239 | { 240 | mes = *(Message*)radio.DATA; 241 | validPacket = true; // YES, we have a packet ! 242 | signalStrength = radio.RSSI; 243 | #ifdef DEBUG 244 | Serial.print(mes.devID); 245 | Serial.print(", "); 246 | Serial.print(mes.cmd); 247 | Serial.print(", "); 248 | Serial.print(mes.intVal); 249 | Serial.print(", "); 250 | Serial.print(mes.fltVal); 251 | Serial.print(", RSSI= "); 252 | Serial.println(radio.RSSI); 253 | Serial.print("Node: "); 254 | Serial.println(mes.nodeID); 255 | #endif 256 | } 257 | } 258 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 259 | return validPacket; // return code indicates packet received 260 | } // end recieveData 261 | 262 | // 263 | // 264 | //============== PARSECMD: analyse messages and execute commands received from gateway 265 | // 266 | 267 | void parseCmd() { // parse messages received from the gateway 268 | send0 = false; // initialise all send triggers 269 | send1 = false; 270 | send2 = false; 271 | send3 = false; 272 | send4 = false; 273 | send5 = false; 274 | send6 = false; 275 | send7 = false; 276 | send9 = false; 277 | send16 = false; 278 | send40 = false; 279 | 280 | send92 = false; 281 | 282 | switch (mes.devID) // devID indicates device (sensor) type 283 | { 284 | case (0): // uptime 285 | if (mes.cmd == 1) send0 = true; 286 | break; 287 | case (1): // polling interval in seconds 288 | if (mes.cmd == 0) { // cmd == 0 means write a value 289 | TXinterval = mes.intVal; // change interval to radio packet value 290 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 291 | if (setAck) send1 = true; // send message if required 292 | #ifdef DEBUG 293 | Serial.print("Setting interval to "); 294 | Serial.print(TXinterval); 295 | Serial.println(" seconds"); 296 | #endif 297 | } 298 | else send1 = true; // cmd == 1 is a read request, so send polling interval 299 | break; 300 | case (2): // signal strength 301 | if (mes.cmd == 1) send2 = true; 302 | break; 303 | case (3): // software version 304 | if (mes.cmd == 1) send3 = true; 305 | break; 306 | case (4): // battery level 307 | if (mes.cmd == 1) send4 = true; 308 | break; 309 | case (5): // set ack status 310 | if (mes.cmd == 0) { 311 | if (mes.intVal == 0) setAck = false; 312 | if (mes.intVal == 1) setAck = true; 313 | if (setAck) send5 = true; // acknowledge message ? 314 | } 315 | else send5 = true; // read request means schedule a message 316 | break; 317 | case (6): // set toggle 318 | if (mes.cmd == 0) { 319 | if (mes.intVal == 0) toggleOnButton = false; 320 | if (mes.intVal == 1) toggleOnButton = true; 321 | if (setAck) send6 = true; // acknowledge message ? 322 | } 323 | else send6 = true; 324 | break; 325 | case (7): // timer interval in seconds 326 | if (mes.cmd == 0) { // cmd == 0 means write a value 327 | TIMinterval = mes.intVal; // change interval 328 | if (TIMinterval <5 && TIMinterval !=0) TIMinterval = 5; 329 | if (setAck) send7 = true; // acknowledge message ? 330 | } // cmd == 1 means read a value 331 | else send7 = true; // send timing interval 332 | break; 333 | case (9): // retransmissions 334 | if (mes.cmd == 1) send9 = true; 335 | break; 336 | case (16): // output 337 | if (mes.cmd == 0) { // cmd == 0 means write 338 | if(mes.intVal == 0 || mes.intVal == 1) { 339 | ACT1State = mes.intVal; 340 | digitalWrite(ACT1, ACT1State); 341 | if (setAck) send16 = true; // acknowledge message ? 342 | #ifdef DEBUG 343 | Serial.print("Set LED to "); 344 | Serial.println(ACT1State); 345 | #endif 346 | }} 347 | else send16 = true; // cmd == 1 means read 348 | break; 349 | case (40): // binary input 350 | if (mes.cmd == 1) send40 = true; 351 | break; 352 | 353 | default: send92 = true; // no valid device parsed 354 | } 355 | } // end parseCmd 356 | 357 | // 358 | // 359 | //====================== SENDMSG: sends messages that are flagged for transmission 360 | // 361 | 362 | void sendMsg() { // prepares values to be transmitted 363 | bool tx = false; // transmission flag 364 | mes.nodeID=NODEID; 365 | mes.intVal = 0; 366 | mes.fltVal = 0; 367 | mes.cmd = 0; // '0' means no action needed in gateway 368 | int i; 369 | for ( i = 0; i < sizeof(VERSION); i++){ 370 | mes.payLoad[i] = VERSION[i]; } 371 | mes.payLoad[i] = '\0'; // software version in payload string 372 | 373 | if (wakeUp) { // send wakeUp call 374 | mes.devID = 99; 375 | wakeUp = false; // reset transmission flag for this message 376 | txRadio(); // transmit 377 | } 378 | if (send0) { 379 | mes.devID = 0; 380 | mes.intVal = upTime; // minutes uptime 381 | send0 = false; 382 | txRadio(); 383 | } 384 | if (send1) { // transmission interval 385 | mes.devID = 1; 386 | mes.intVal = TXinterval; // seconds (integer) 387 | send1 = false; 388 | txRadio(); 389 | } 390 | if (send2) { 391 | mes.devID = 2; 392 | mes.intVal = signalStrength; // signal strength (integer) 393 | send2 = false; 394 | txRadio(); 395 | } 396 | if (send3) { // node software version (string) 397 | mes.devID = 3; // already stored in payload string 398 | send3 = false; 399 | txRadio(); 400 | } 401 | if (send4) { // measure voltage.. 402 | mes.devID = 4; 403 | long result; // Read 1.1V reference against AVcc 404 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 405 | delay(2); // Wait for Vref to settle 406 | ADCSRA |= _BV(ADSC); // Convert 407 | while (bit_is_set(ADCSRA,ADSC)); 408 | result = ADCL; 409 | result |= ADCH<<8; 410 | result = 1126400L / result; // Back-calculate in mV 411 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 412 | txRadio(); 413 | send4 = false; 414 | } 415 | if (send5) { // Acknowledge on 'SET' 416 | mes.devID = 5; 417 | if (setAck) mes.intVal = 1; else mes.intVal = 0;// state (integer) 418 | send5 = false; 419 | txRadio(); 420 | } 421 | if (send6) { // Toggle on Buttonpress 422 | mes.devID = 6; 423 | if (toggleOnButton) mes.intVal = 1; // read state of toggle flag 424 | else mes.intVal = 0; // state (integer) 425 | send6 = false; 426 | txRadio(); 427 | } 428 | if (send7) { // timer interval 429 | mes.devID = 7; 430 | mes.intVal = TIMinterval; // seconds (integer) 431 | send7 = false; 432 | txRadio(); 433 | } 434 | if (send9) { // number of retransmissions 435 | mes.devID = 9; 436 | mes.intVal = numtx; // number (integer) 437 | send9 = false; 438 | txRadio(); 439 | } 440 | if (send16) { // state of Actuator 1 441 | mes.devID = 16; 442 | mes.intVal = ACT1State; // state (integer) 443 | send16 = false; 444 | txRadio(); 445 | } 446 | if (send40) { // Binary input read 447 | mes.devID = 40; 448 | if (curState == LOW) mes.intVal = 1; // state (integer) 449 | send40 = false; 450 | txRadio(); 451 | } 452 | if (send92) { // error message invalid device 453 | mes.intVal = mes.devID; 454 | mes.devID = 92; 455 | send92 = false; 456 | txRadio(); 457 | } 458 | 459 | } 460 | // 461 | // 462 | //======================= TXRADIO 463 | // 464 | 465 | void txRadio() // Transmits the 'mes'-struct to the gateway 466 | { 467 | retx = true; 468 | int i = 0; 469 | 470 | while (retx && i<6) { 471 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes),5)) { 472 | retx = false; 473 | #ifdef DEBUG 474 | Serial.print(" message "); 475 | Serial.print(mes.devID); 476 | Serial.println(" sent..."); 477 | #endif 478 | } else delay(500); 479 | i++; 480 | } 481 | numtx = i; // store number of retransmissions needed 482 | #ifdef DEBUG 483 | if (retx) Serial.println("No connection...") 484 | #endif 485 | ;} // end txRadio 486 | 487 | 488 | 489 | 490 | 491 | 492 | -------------------------------------------------------------------------------- /Openhab Example/Readme.txt: -------------------------------------------------------------------------------- 1 | This example contains the configuration files for the following setup: 2 | 3 | node 2: DIG node with local output toggle 4 | node 6: DHT node with local output toggle and temperature / humidity measurement 5 | node 4: RC node that controls a klikaanklikuit switch at address C1 6 | 7 | 8 | The standard DIG and DHT nodes have been configured to: 9 | 10 | - send an state message after every write commando from openhab; ACK has been set to TRUE. 11 | - send a state message after each local toggle of the output. 12 | 13 | In this way the node sends a status message after each output change, whether it is generated by openhab or by pushing the button on the node. 14 | The rules-file contains rules to inspect these messages, and update the Openhab status of the output accordingly. 15 | In this way the openhab status is set by a feedback message received from the node, in this way always reflecting the true state. If somehow the command has not reached the node, (bad radiosignal) the status in openhab is not changed. 16 | 17 | Most of the time a small delay can be observed between pressing the button in the Openhab UI and the state change in the UI. This delay is due to the time it needs to process and send/receive all messages. 18 | 19 | ITEMS 20 | In the items-file a switch is configured to store the received status of the output. The received commands (ON/OFF) are translated into states that Openhab understands (OPEN/CLOSED) for a switch. 21 | To display the status in the UI the following icons must be copied in folder /usr/share/openhab/webapps/images: 22 | 23 | light-on.png must be copied to lamp-open.png 24 | light-off.png must be copied to lamp-closed.png 25 | 26 | RULES 27 | In this file rules are included to: 28 | - read RSSI values on node 2 once a minute 29 | - update output values for node2 and node 6 30 | - switch a light on and off via node 4 (klikaanklikuit) at preset times each day 31 | 32 | -------------------------------------------------------------------------------- /Openhab Example/base.items: -------------------------------------------------------------------------------- 1 | 2 | /* Numbers to store data values */ 3 | Number RSSI2 "RSSI [%d dBm]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev02:state:default]"}Number TEMP2 "Temperature [%.1f °C]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev48:state:default]"} 4 | Number HUM2 "Humidity [%.1f %%]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev49:state:default]"} 5 | 6 | /* Switch to write to the output */ 7 | Switch OUT2 {mqtt=">[mosquitto:home/rfm_gw/sb/node02/dev16:command:ON:ON],>[mosquitto:home/rfm_gw/sb/node02/dev16:command:OFF:OFF]"} 8 | Switch OUT6 {mqtt=">[mosquitto:home/rfm_gw/sb/node06/dev16:command:ON:ON],>[mosquitto:home/rfm_gw/sb/node06/dev16:command:OFF:OFF]"} 9 | 10 | /* String to acquire the output state */ 11 | String getSTAT6 "get STAT6" {mqtt=">[mosquitto:home/rfm_gw/sb/node06/dev16:command:*:default]"} 12 | String getRSSI2 "get RSSI" {mqtt=">[mosquitto:home/rfm_gw/sb/node02/dev02:command:*:default]"} 13 | 14 | /* Contacts to read the output state */ 15 | Contact STAT2 "Status [%s]" {mqtt="<[mosquitto:home/rfm_gw/nb/node02/dev16:state:OPEN:ON],<[mosquitto:home/rfm_gw/nb/node02/dev16:state:CLOSED:OFF]"} 16 | Contact STAT6 "Status [%s]" {mqtt="<[mosquitto:home/rfm_gw/nb/node06/dev16:state:OPEN:ON],<[mosquitto:home/rfm_gw/nb/node06/dev16:state:CLOSED:OFF]"} 17 | 18 | /* Remote Controlled switch (KLIKAANKLIKUIT) item */ 19 | Switch KAKUC1 {mqtt=">[mosquitto:home/rfm_gw/sb/node04/dev72:command:ON:KAKU C1 ON],>[mosquitto:home/rfm_gw/sb/node04/dev72:command:OFF:KAKU C1 OFF]"} 20 | 21 | /* NTP binding demo item */ 22 | DateTime Date "Date [%1$tA, %1$td.%1$tm.%1$tY]" { ntp="Europe/Amsterdam:nl_NL" } 23 | 24 | -------------------------------------------------------------------------------- /Openhab Example/base.rules: -------------------------------------------------------------------------------- 1 | // 2 | // rules file for base home Computourist@gmail.com November 5th, 2015 3 | // 4 | 5 | import org.openhab.core.library.types.* 6 | import org.openhab.core.persistence.* 7 | import org.openhab.model.script.actions.* 8 | import java.util.Random 9 | 10 | // 11 | // refresh rules 12 | // 13 | 14 | rule "refresh RSSI2" // periodically refresh value for signal strength on node 2 15 | when 16 | Time cron "0 0/1 * * * ?" 17 | then 18 | sendCommand(getRSSI2, "READ") 19 | end 20 | 21 | // 22 | // update whenever a local switch is toggled 23 | // 24 | 25 | rule "Update OUT2" // update state OUT2 after local node switch toggle 26 | when 27 | Item STAT2 received update 28 | then 29 | if (STAT2.state==OPEN) { 30 | postUpdate(OUT2, ON)} 31 | if (STAT2.state==CLOSED) { 32 | postUpdate(OUT2, OFF)} 33 | // logInfo("stat2 changed: ", STAT2.state.toString()) 34 | 35 | end 36 | 37 | 38 | rule "Update OUT6" // update state OUT6 after local node switch toggle 39 | when 40 | Item STAT6 received update 41 | then 42 | if (STAT6.state==OPEN) { 43 | postUpdate(OUT6, ON) } 44 | if (STAT6.state==CLOSED) { 45 | postUpdate(OUT6, OFF)} 46 | end 47 | 48 | 49 | 50 | // 51 | // Timing schedule ******************************* 52 | // 53 | 54 | rule "Living on" // switch on KAKU C1 18:20 55 | when 56 | Time cron "0 20 18 * * ?" 57 | then 58 | sendCommand(KAKUC1,ON) 59 | end 60 | 61 | rule "Living off" // switch off KAKU C1 22:46 62 | when 63 | Time cron "0 46 22 * * ?" 64 | then 65 | sendCommand(KAKUC1,OFF) 66 | end -------------------------------------------------------------------------------- /Openhab Example/base.sitemap: -------------------------------------------------------------------------------- 1 | sitemap base label="Base House" 2 | 3 | { 4 | Frame label="Controls" { 5 | Switch item=OUT2 label="Node 2" icon="light" 6 | Text item=STAT2 label="status node 2" icon="lamp" 7 | Switch item=OUT6 label="Node 6" icon="light" 8 | Text item=STAT6 label="status node 6" icon="lamp" 9 | } 10 | Frame label="Node 2" { 11 | Text item=TEMP2 12 | Text item=HUM2 13 | Text item=RSSI2 14 | } 15 | Frame label="Date" { 16 | Text item=Date 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Arduino - RFM69 based sensors and MQTT gateway 2 | ================ 3 | 4 | May 2016: Published a Wifi connected ESP8266 node here: https://github.com/computourist/ESP8266-MQTT-client 5 | - it uses the same message format as the RFM nodes 6 | - it is a direct mqtt client, no gateway needed 7 | - RFM and ESP nodes can be mixed in the same setup 8 | 9 | ================ 10 | 11 | March 2016: corrected swapped NSS signals in schematics for gateway 2.4 12 | 13 | ================ 14 | 15 | February 2016: added schematics for gateway 2.4 and DHT end node 16 | 17 | ================ 18 | 19 | January 2016: published Gateway version 2.4: 20 | - this version is now compatible with Arduino IDE again 21 | - DEBUG function split into an MQTT and a radio part. Debugging can be done one at a time. This solves memory constraints. 22 | 23 | ================ 24 | 25 | November 2015: Openhab example added, showing the use of node-generated status messages to sync Openhab with local output toggles. 26 | 27 | ================ 28 | 29 | Changes in Gateway version 2.3: 30 | - implemented system device 9: number of retransmissions needed in the radio link 31 | - removed some of the debug code as a result of memory constraints 32 | 33 | Version compatibility: 34 | 35 | - GW release 2.2: DHT2.1 LCD2.0 RC1.0 RFID1.0 36 | 37 | - GW release 2.3: DHT2.2 LCD2.1 RC2.0 DIG2.2 38 | 39 | 40 | RFID has not been upgraded yet since the code is not stable. (it will work -unstable- with GW2.3 though) 41 | 42 | Changes in Gateway version 2.2: 43 | - changed handling of binary input devices to improve compatibility with Openhab 44 | - improved RSSI reporting 45 | 46 | 47 | Changes in Gateway version 2.1: 48 | - uniform handling of binary input devices 49 | - transparant exchange of string data (device 72) added 50 | - minor bug fixing 51 | 52 | Changes in Gateway version 2: 53 | - increased data exchange data block 54 | - implemented standard device numbering 55 | - removed leading spaces in decimal sensor data 56 | - implemented uptime counter 57 | - implemented error checking & reporting 58 | - implemented uptime and version reporting in gateway 59 | 60 | ____________________________________________________________________________________________________________________ 61 | The setup consists of two types of devices: 62 | 63 | - an end node that measures parameters, changes output states and communicates over radio with a central gateway 64 | - a gateway node that connects to end node over wireless and publishes/receives MQTT messages to/from a broker. 65 | 66 | The communication between MQTT broker and multiple end nodes is duplex, meaning: 67 | - The state of an end node device/parameter can be queried thru the broker at any time 68 | - The end node has outputs, so external devices can be controlled over MQTT 69 | - Sensor commands can be acknowledged by the end node 70 | - Loss of radio signal to a certain end node is indicated to the MQTT broker 71 | - End nodes can send sensor data on regular intervals, on incoming query or event-based 72 | - MQTT message syntax can easily be altered by only changing the gateway code 73 | - Multiple end nodes can be addressed by a single gateway 74 | 75 | Communication between gateway and nodes is over an encrypted wireless link and handshake mechanisms are used to guarantee succesfull transmission. Radio link errors are reported to the MQTT broker. 76 | Communication between gateway and MQTT broker is over fixed ethernet. 77 | 78 | The end node software is capable of: 79 | - switching one or more outputs (LED, relay) 80 | - measuring temperature, humidity, battery voltage 81 | - set transmission interval in seconds 82 | - switch off automatic regular transmission 83 | - report software version 84 | - report radio signal strength 85 | - monitor button presses 86 | - set button action to local toggle, local timer or generation of an MQTT event message 87 | - set button press timer interval in seconds 88 | 89 | The gateway software is capable of: 90 | - Communicating with end nodes and with the MQTT broker 91 | - Automatically set up connetions tp MQTT broker and end nodes 92 | - Translate the internal message format to MQTT messages and vice versa 93 | - Detect radio signal loss and report this to the MQTT broker 94 | - Publish end node events in a northbound message stream 95 | - Subscribe to a southbound message stream to receive, parse messages and address the corresponding end node 96 | - Manually produce event queries in debug mode 97 | 98 | -------------------------------------------------------------------------------- /RFID end node/RFM_RFID_node_10.ino: -------------------------------------------------------------------------------- 1 | // RFM69 RFID node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will: 4 | // - send sensor data periodically 5 | // - detect and read RFID cards and send the UID to the MQTT broker; 6 | // 7 | // 8 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 and RFID-RC522. 9 | // Power requirements dictate that a reparate 3.3 Volts regulator is used to power both RFM69 and RFID reader 10 | // A RED led (D7) is used to indicate an RFID card has been detected and read. It will stay on during HOLDOFF msec. 11 | // 12 | // Current defined devices are: 13 | // 14 | // 0 uptime: read uptime node in minutes 15 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 16 | // 2 RSSI: read radio signal strength 17 | // 3 Version: read version node software 18 | // 4 voltage: read battery level 19 | // 5 ACK: read/set acknowledge message after a 'set' request 20 | // 7 timer: read/set timer for LED activation, 0 means no timer 21 | // 22 | // 72 UID: send UID of detected RFID token 23 | // 90 error: tx only: error message if no wireless connection (generated by gateway) 24 | // 92 error: tx only: device not supported 25 | // 99 wakeup: tx only: first message sent on node startup 26 | // 27 | // 28 | // Pin layout used: 29 | // ------------------------------------------------ 30 | // MFRC522 RFM69 Arduino 31 | // Reader/PCD Uno 32 | // Signal Pin Pin Pin 33 | // ------------------------------------------------ 34 | // INT0 - DIO0 D2 35 | // REDLED - - D7 36 | // SPI SS RFM - NSS D4 37 | // RST/Reset RST - D9 38 | // SPI SS RFID SDA(SS) - D10 39 | // SPI MOSI MOSI MOSI D11 40 | // SPI MISO MISO MISO D12 41 | // SPI SCK SCK SCK D13 42 | // 43 | // 44 | // 45 | // A debug mode is included which outputs messages on the serial output 46 | // 47 | // MFRC522 library at: https://github.com/miguelbalboa/rfid 48 | // Make sure to change the library file: MFRC522.cpp: 49 | // - add "cli();" to every occurrence of "digitalWrite(_chipSelectPin,LOW)" 50 | // - add "sei();" to every occurrence of "digitalWrite(_chipSelectPin,HIGH)" 51 | // 52 | // 53 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 54 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 55 | // 56 | // version 1.0 by Computourist@gmail.com March 2015 57 | // 58 | #include 59 | #include 60 | #include 61 | 62 | 63 | // 64 | // CONFIGURATION PARAMETERS 65 | // 66 | #define NODEID 5 // unique node ID within the closed network 67 | #define GATEWAYID 1 // node ID of the Gateway is always 1 68 | #define NETWORKID 100 // network ID of the network 69 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 70 | #define DEBUG // uncomment for debugging 71 | #define VERSION "RFID V1.0" // this value can be queried as device 3 72 | 73 | // Wireless settings Match frequency to the hardware version of the radio 74 | 75 | //#define FREQUENCY RF69_433MHZ 76 | #define FREQUENCY RF69_868MHZ 77 | //#define FREQUENCY RF69_915MHZ 78 | 79 | #define IS_RFM69HW // uncomment only for RFM69HW! 80 | #define ACK_TIME 50 // max # of ms to wait for an ack 81 | 82 | // pin setting 83 | #define RFID_RST 9 // reset pin RC522 84 | #define RFID_SS 10 // Slave Select pin RC522 85 | #define RFM_SS 4 // Slave Select pin RFM69 86 | #define REDLED 7 // Red LED pin 87 | #define SERIAL_BAUD 115200 88 | #define HOLDOFF 2000 // blocking period between RFID detection 89 | 90 | // 91 | // STARTUP DEFAULTS 92 | // 93 | long TXinterval = 20; // periodic transmission interval in seconds 94 | 95 | 96 | // 97 | // VARIABLES 98 | // 99 | long lastPeriod = -1; // timestamp last transmission 100 | long lastOn = -1; // timestamp last buttonpress 101 | long lastMinute = -1; // timestamp last minute 102 | long upTime = 0; // uptime in minutes 103 | 104 | int signalStrength; // radio signal strength 105 | bool setAck = false; // send ACK message on 'SET' request 106 | bool send0, send1, send2, send3, send4; 107 | bool send5, send7; 108 | bool send92; // message triggers 109 | bool promiscuousMode = false; // only listen to nodes within the closed network 110 | bool wakeUp = true; // wakeup flag 111 | long lastCardDetect=-1; // timestamp of last card detection 112 | bool cardDetect = false; // flag to indicate an RFID card has been detected 113 | bool block=false; // block RFID reader during holdoff 114 | bool redLedState=false; // state of red LED 115 | unsigned char UID[5] ; // holds RFID code in numbers 116 | String RFID_Code; // holds RFID code in ASCII 117 | 118 | 119 | 120 | typedef struct { // Radio packet format 121 | int nodeID; // node identifier 122 | int devID; // device identifier 123 | int cmd; // read or write 124 | long intVal; // integer payload 125 | float fltVal; // floating payload 126 | char payLoad[32]; // string payload 127 | } Message; 128 | 129 | Message mes; 130 | 131 | 132 | 133 | MFRC522 mfrc522(RFID_SS, RFID_RST); // Create MFRC522 instance 134 | 135 | RFM69 radio; // Create RFM69 instance 136 | 137 | // 138 | //===================== SETUP ======================================== 139 | // 140 | void setup() { 141 | #ifdef DEBUG 142 | Serial.begin(SERIAL_BAUD); 143 | #endif 144 | pinMode(REDLED, OUTPUT); // set LED output 145 | digitalWrite(REDLED, LOW); 146 | radio.setCS(RFM_SS); // set SS pin 147 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 148 | #ifdef IS_RFM69HW 149 | radio.setHighPower(); // only for RFM69HW! 150 | #endif 151 | radio.encrypt(ENCRYPTKEY); // set radio encryption 152 | radio.promiscuous(promiscuousMode); // only listen to closed network 153 | wakeUp = true; // send wakeup message 154 | SPI.begin(); 155 | mfrc522.PCD_Init(); 156 | 157 | #ifdef DEBUG 158 | Serial.print("Node Software Version "); 159 | Serial.println(VERSION); 160 | Serial.print("\nTransmitting at "); 161 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 162 | Serial.println(" Mhz..."); 163 | #endif 164 | } // end setup 165 | 166 | // 167 | // 168 | //==================== MAIN ======================================== 169 | // 170 | void loop() { 171 | block = (millis()-lastCardDetect) < HOLDOFF; 172 | 173 | if (!block) { 174 | if (redLedState) { // turn off red LED 175 | redLedState = false; 176 | digitalWrite(REDLED,LOW); 177 | } 178 | if ( mfrc522.PICC_IsNewCardPresent()) { // Look for new cards 179 | lastCardDetect = millis(); 180 | redLedState = true; 181 | digitalWrite(REDLED,HIGH); 182 | } 183 | 184 | if ( mfrc522.PICC_ReadCardSerial()) { // Select one of the cards 185 | cardDetect = true; 186 | Serial.println("Scanned PICC's UID:"); 187 | for (int i = 0; i < 4; i++) { // 188 | UID[i] = mfrc522.uid.uidByte[i]; 189 | Serial.print(UID[i], HEX); 190 | Serial.print(" "); 191 | } 192 | 193 | Serial.println(""); 194 | mfrc522.PICC_HaltA(); // Stop reading 195 | } 196 | 197 | } 198 | 199 | // RECEIVE radio input 200 | // 201 | if (receiveData()) parseCmd(); // receive and parse any radio input 202 | 203 | 204 | // UPTIME 205 | // 206 | 207 | if (lastMinute != (millis()/60000)) { // another minute passed ? 208 | lastMinute = millis()/60000; 209 | upTime++; 210 | } 211 | 212 | // PERIODIC TRANSMISSION 213 | // 214 | 215 | if (TXinterval > 0) 216 | { 217 | int currPeriod = millis()/(TXinterval*1000); 218 | if (currPeriod != lastPeriod) { // interval elapsed ? 219 | lastPeriod = currPeriod; 220 | 221 | // list of sensordata to be sent periodically.. 222 | // remove comment to include parameter in transmission 223 | // send1 = true; // send transmission interval 224 | send2 = true; // signal strength 225 | // send4 = true; // voltage level 226 | // send16 = true; // actuator state 227 | 228 | } 229 | } 230 | 231 | // SEND RADIO PACKETS 232 | // 233 | 234 | sendMsg(); // send any radio messages 235 | 236 | } // end loop 237 | 238 | // 239 | // 240 | //===================== FUNCTIONS ========================================== 241 | 242 | // 243 | //======== RECEIVEDATA : receive data from gateway over radio 244 | // 245 | 246 | bool receiveData() { 247 | bool validPacket = false; 248 | if (radio.receiveDone()) // check for received packets 249 | { 250 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 251 | #ifdef DEBUG 252 | Serial.println("invalid message structure..") 253 | #endif 254 | ; 255 | else 256 | { 257 | mes = *(Message*)radio.DATA; 258 | validPacket = true; // YES, we have a packet ! 259 | signalStrength = radio.RSSI; 260 | #ifdef DEBUG 261 | Serial.print(mes.devID); 262 | Serial.print(", "); 263 | Serial.print(mes.cmd); 264 | Serial.print(", "); 265 | Serial.print(mes.intVal); 266 | Serial.print(", "); 267 | Serial.print(mes.fltVal); 268 | Serial.print(", RSSI= "); 269 | Serial.println(radio.RSSI); 270 | Serial.print("Node: "); 271 | Serial.println(mes.nodeID); 272 | #endif 273 | } 274 | } 275 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 276 | return validPacket; // return code indicates packet received 277 | } // end recieveData 278 | 279 | // 280 | // 281 | //============== PARSECMD: analyse messages and execute commands received from gateway 282 | // 283 | 284 | void parseCmd() { // parse messages received from the gateway 285 | 286 | send0 = false; // initialise all send triggers 287 | send1 = false; 288 | send2 = false; 289 | send3 = false; 290 | send4 = false; 291 | send5 = false; 292 | send7 = false; 293 | send92 = false; 294 | 295 | switch (mes.devID) // devID indicates device (sensor) type 296 | { 297 | case (0): // uptime 298 | if (mes.cmd == 1) send0 = true; 299 | break; 300 | case (1): // polling interval in seconds 301 | if (mes.cmd == 0) { // cmd == 0 means write a value 302 | TXinterval = mes.intVal; // change interval to radio packet value 303 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 304 | if (setAck) send1 = true; // send message if required 305 | #ifdef DEBUG 306 | Serial.print("Setting interval to "); 307 | Serial.print(TXinterval); 308 | Serial.println(" seconds"); 309 | #endif 310 | } 311 | else send1 = true; // cmd == 1 is a read request, so send polling interval 312 | break; 313 | case (2): // signal strength 314 | if (mes.cmd == 1) send2 = true; 315 | break; 316 | case (3): // software version 317 | if (mes.cmd == 1) send3 = true; 318 | break; 319 | case (4): // battery level 320 | if (mes.cmd == 1) send4 = true; 321 | break; 322 | case (5): // set ack status 323 | if (mes.cmd == 0) { 324 | if (mes.intVal == 0) setAck = false; 325 | if (mes.intVal == 1) setAck = true; 326 | if (setAck) send5 = true; // acknowledge message ? 327 | } 328 | else send5 = true; // read request means schedule a message 329 | break; 330 | 331 | default: send92 = true; // no valid device parsed 332 | } 333 | } // end parseCmd 334 | 335 | // 336 | // 337 | //====================== SENDMSG: sends messages that are flagged for transmission 338 | // 339 | 340 | void sendMsg() { // prepares values to be transmitted 341 | bool tx = false; // transmission flag 342 | mes.nodeID=NODEID; 343 | mes.intVal = 0; 344 | mes.fltVal = 0; 345 | mes.cmd = 0; // '0' means no action needed in gateway 346 | int i; 347 | for ( i = 0; i < sizeof(VERSION); i++){ 348 | mes.payLoad[i] = VERSION[i]; } 349 | mes.payLoad[i] = '\0'; // software version in payload string 350 | 351 | if (wakeUp) { // send wakeUp call 352 | mes.devID = 99; 353 | wakeUp = false; // reset transmission flag for this message 354 | txRadio(); // transmit 355 | } 356 | if (send0) { 357 | mes.devID = 0; 358 | mes.intVal = upTime; // minutes uptime 359 | send0 = false; 360 | txRadio(); 361 | } 362 | if (send1) { // transmission interval 363 | mes.devID = 1; 364 | mes.intVal = TXinterval; // seconds (integer) 365 | send1 = false; 366 | txRadio(); 367 | } 368 | if (send2) { 369 | mes.devID = 2; 370 | mes.intVal = signalStrength; // signal strength (integer) 371 | send2 = false; 372 | txRadio(); 373 | } 374 | if (send3) { // node software version (string) 375 | mes.devID = 3; // already stored in payload string 376 | send3 = false; 377 | txRadio(); 378 | } 379 | if (send4) { // measure voltage.. 380 | mes.devID = 4; 381 | long result; // Read 1.1V reference against AVcc 382 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 383 | delay(2); // Wait for Vref to settle 384 | ADCSRA |= _BV(ADSC); // Convert 385 | while (bit_is_set(ADCSRA,ADSC)); 386 | result = ADCL; 387 | result |= ADCH<<8; 388 | result = 1126400L / result; // Back-calculate in mV 389 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 390 | txRadio(); 391 | send4 = false; 392 | } 393 | if (send5) { // Acknowledge on 'SET' 394 | mes.devID = 5; 395 | if (setAck) mes.intVal = 1; else mes.intVal = 0;// state (integer) 396 | send5 = false; 397 | txRadio(); 398 | } 399 | 400 | 401 | if (cardDetect) { // RFID card detected 402 | mes.devID = 72; 403 | RFID_Code=""; 404 | for ( i = 0; i < 4; i++){ // fill string with 4 Hex numbers 405 | RFID_Code += String(UID[i],HEX); 406 | } 407 | RFID_Code.toUpperCase(); 408 | for (i= 0; i<9 ; i++){ // copy string (6 characters) to payload 409 | mes.payLoad[i] = RFID_Code[i]; 410 | } 411 | cardDetect = false; 412 | txRadio(); 413 | } 414 | if (send92) { // error message invalid device 415 | mes.intVal = mes.devID; 416 | mes.devID = 92; 417 | send92 = false; 418 | txRadio(); 419 | } 420 | 421 | } 422 | // 423 | // 424 | //======================= TXRADIO 425 | // 426 | 427 | void txRadio() // Transmits the 'mes'-struct to the gateway 428 | { 429 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes))) 430 | #ifdef DEBUG 431 | {Serial.print(" message "); 432 | Serial.print(mes.devID); 433 | Serial.println(" sent...");} 434 | else Serial.println("No connection...") 435 | #endif 436 | ;} // end txRadio 437 | 438 | 439 | 440 | 441 | 442 | 443 | -------------------------------------------------------------------------------- /RFID end node/RFM_RFID_node_20.ino: -------------------------------------------------------------------------------- 1 | // RFM69 RFID node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will: 4 | // - send sensor data periodically 5 | // - detect and read RFID cards and send the UID to the MQTT broker; 6 | // 7 | // 8 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 and RFID-RC522. 9 | // Power requirements dictate that a reparate 3.3 Volts regulator is used to power both RFM69 and RFID reader 10 | // A RED led (D7) is used to indicate an RFID card has been detected and read. It will stay on during HOLDOFF msec. 11 | // 12 | // Current defined devices are: 13 | // 14 | // 0 uptime: read uptime node in minutes 15 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 16 | // 2 RSSI: read radio signal strength 17 | // 3 Version: read version node software 18 | // 4 voltage: read battery level 19 | // 5 ACK: read/set acknowledge message after a 'set' request 20 | // 7 timer: read/set timer for LED activation, 0 means no timer 21 | // 22 | // 72 UID: send UID of detected RFID token 23 | // 90 error: tx only: error message if no wireless connection (generated by gateway) 24 | // 92 error: tx only: device not supported 25 | // 99 wakeup: tx only: first message sent on node startup 26 | // 27 | // 28 | // Pin layout used: 29 | // ------------------------------------------------ 30 | // MFRC522 RFM69 Arduino 31 | // Reader/PCD Uno 32 | // Signal Pin Pin Pin 33 | // ------------------------------------------------ 34 | // INT0 - DIO0 D2 35 | // REDLED - - D7 36 | // SPI SS RFM - NSS D4 37 | // RST/Reset RST - D9 38 | // SPI SS RFID SDA(SS) - D10 39 | // SPI MOSI MOSI MOSI D11 40 | // SPI MISO MISO MISO D12 41 | // SPI SCK SCK SCK D13 42 | // 43 | // 44 | // 45 | // A debug mode is included which outputs messages on the serial output 46 | // 47 | // MFRC522 library at: https://github.com/miguelbalboa/rfid 48 | // 49 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 50 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 51 | // 52 | // version 1.0 by Computourist@gmail.com March 2015 53 | // version 2.0 by Lewishollow & Computourist Jan 2016 54 | // 55 | #include 56 | #include 57 | #include 58 | 59 | 60 | // 61 | // CONFIGURATION PARAMETERS 62 | // 63 | #define NODEID 5 // unique node ID within the closed network 64 | #define GATEWAYID 1 // node ID of the Gateway is always 1 65 | #define NETWORKID 100 // network ID of the network 66 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 67 | #define DEBUG // uncomment for debugging 68 | #define VERSION "RFID V2.0" // this value can be queried as device 3 69 | 70 | // Wireless settings Match frequency to the hardware version of the radio 71 | 72 | //#define FREQUENCY RF69_433MHZ 73 | #define FREQUENCY RF69_868MHZ 74 | //#define FREQUENCY RF69_915MHZ 75 | 76 | #define IS_RFM69HW // uncomment only for RFM69HW! 77 | #define ACK_TIME 50 // max # of ms to wait for an ack 78 | 79 | // pin setting 80 | #define RFID_RST 9 // reset pin RC522 81 | #define RFID_SS 10 // Slave Select pin RC522 82 | #define RFM_SS 4 // Slave Select pin RFM69 83 | #define REDLED 7 // Red LED pin 84 | #define SERIAL_BAUD 115200 85 | #define HOLDOFF 2000 // blocking period between RFID detection 86 | 87 | // 88 | // STARTUP DEFAULTS 89 | // 90 | long TXinterval = 20; // periodic transmission interval in seconds 91 | 92 | 93 | // 94 | // VARIABLES 95 | // 96 | long lastPeriod = -1; // timestamp last transmission 97 | long lastOn = -1; // timestamp last buttonpress 98 | long lastMinute = -1; // timestamp last minute 99 | long upTime = 0; // uptime in minutes 100 | 101 | int signalStrength; // radio signal strength 102 | bool setAck = false; // send ACK message on 'SET' request 103 | bool send0, send1, send2, send3, send4; 104 | bool send5, send7; 105 | bool send92; // message triggers 106 | bool promiscuousMode = false; // only listen to nodes within the closed network 107 | bool wakeUp = true; // wakeup flag 108 | long lastCardDetect=-1; // timestamp of last card detection 109 | bool cardDetect = false; // flag to indicate an RFID card has been detected 110 | bool block=false; // block RFID reader during holdoff 111 | bool redLedState=false; // state of red LED 112 | unsigned char UID[5] ; // holds RFID code in numbers 113 | String RFID_Code; // holds RFID code in ASCII 114 | 115 | 116 | 117 | typedef struct { // Radio packet format 118 | int nodeID; // node identifier 119 | int devID; // device identifier 120 | int cmd; // read or write 121 | long intVal; // integer payload 122 | float fltVal; // floating payload 123 | char payLoad[32]; // string payload 124 | } Message; 125 | 126 | Message mes; 127 | 128 | 129 | 130 | MFRC522 mfrc522(RFID_SS, RFID_RST); // Create MFRC522 instance 131 | 132 | RFM69 radio; // Create RFM69 instance 133 | 134 | // 135 | //===================== SETUP ======================================== 136 | // 137 | void setup() { 138 | #ifdef DEBUG 139 | Serial.begin(SERIAL_BAUD); 140 | #endif 141 | pinMode(REDLED, OUTPUT); // set LED output 142 | digitalWrite(REDLED, LOW); 143 | radio.setCS(RFM_SS); // set SS pin 144 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 145 | #ifdef IS_RFM69HW 146 | radio.setHighPower(); // only for RFM69HW! 147 | #endif 148 | radio.encrypt(ENCRYPTKEY); // set radio encryption 149 | radio.promiscuous(promiscuousMode); // only listen to closed network 150 | wakeUp = true; // send wakeup message 151 | SPI.begin(); 152 | mfrc522.PCD_Init(); 153 | 154 | #ifdef DEBUG 155 | Serial.print("Node Software Version "); 156 | Serial.println(VERSION); 157 | Serial.print("\nTransmitting at "); 158 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 159 | Serial.println(" Mhz..."); 160 | #endif 161 | } // end setup 162 | 163 | // 164 | // 165 | //==================== MAIN ======================================== 166 | // 167 | void loop() { 168 | block = (millis()-lastCardDetect) < HOLDOFF; 169 | cli(); 170 | if (!block) { 171 | if (redLedState) { // turn off red LED 172 | redLedState = false; 173 | digitalWrite(REDLED,LOW); 174 | } 175 | if ( mfrc522.PICC_IsNewCardPresent()) { // Look for new cards 176 | lastCardDetect = millis(); 177 | redLedState = true; 178 | digitalWrite(REDLED,HIGH); 179 | } 180 | 181 | if ( mfrc522.PICC_ReadCardSerial()) { // Select one of the cards 182 | cardDetect = true; 183 | Serial.println("Scanned PICC's UID:"); 184 | for (int i = 0; i < 4; i++) { // 185 | UID[i] = mfrc522.uid.uidByte[i]; 186 | Serial.print(UID[i], HEX); 187 | Serial.print(" "); 188 | } 189 | 190 | Serial.println(""); 191 | mfrc522.PICC_HaltA(); // Stop reading 192 | } 193 | 194 | } 195 | sei(); 196 | // RECEIVE radio input 197 | // 198 | if (receiveData()) parseCmd(); // receive and parse any radio input 199 | 200 | 201 | // UPTIME 202 | // 203 | 204 | if (lastMinute != (millis()/60000)) { // another minute passed ? 205 | lastMinute = millis()/60000; 206 | upTime++; 207 | } 208 | 209 | // PERIODIC TRANSMISSION 210 | // 211 | 212 | if (TXinterval > 0) 213 | { 214 | int currPeriod = millis()/(TXinterval*1000); 215 | if (currPeriod != lastPeriod) { // interval elapsed ? 216 | lastPeriod = currPeriod; 217 | 218 | // list of sensordata to be sent periodically.. 219 | // remove comment to include parameter in transmission 220 | // send1 = true; // send transmission interval 221 | send2 = true; // signal strength 222 | // send4 = true; // voltage level 223 | // send16 = true; // actuator state 224 | 225 | } 226 | } 227 | 228 | // SEND RADIO PACKETS 229 | // 230 | 231 | sendMsg(); // send any radio messages 232 | 233 | } // end loop 234 | 235 | // 236 | // 237 | //===================== FUNCTIONS ========================================== 238 | 239 | // 240 | //======== RECEIVEDATA : receive data from gateway over radio 241 | // 242 | 243 | bool receiveData() { 244 | bool validPacket = false; 245 | cli(); 246 | if (radio.receiveDone()) // check for received packets 247 | { 248 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 249 | #ifdef DEBUG 250 | Serial.println("invalid message structure..") 251 | #endif 252 | ; 253 | else 254 | { 255 | mes = *(Message*)radio.DATA; 256 | validPacket = true; // YES, we have a packet ! 257 | signalStrength = radio.RSSI; 258 | #ifdef DEBUG 259 | Serial.print(mes.devID); 260 | Serial.print(", "); 261 | Serial.print(mes.cmd); 262 | Serial.print(", "); 263 | Serial.print(mes.intVal); 264 | Serial.print(", "); 265 | Serial.print(mes.fltVal); 266 | Serial.print(", RSSI= "); 267 | Serial.println(radio.RSSI); 268 | Serial.print("Node: "); 269 | Serial.println(mes.nodeID); 270 | #endif 271 | } 272 | } 273 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 274 | sei(); 275 | return validPacket; // return code indicates packet received 276 | } // end recieveData 277 | 278 | // 279 | // 280 | //============== PARSECMD: analyse messages and execute commands received from gateway 281 | // 282 | 283 | void parseCmd() { // parse messages received from the gateway 284 | 285 | send0 = false; // initialise all send triggers 286 | send1 = false; 287 | send2 = false; 288 | send3 = false; 289 | send4 = false; 290 | send5 = false; 291 | send7 = false; 292 | send92 = false; 293 | 294 | switch (mes.devID) // devID indicates device (sensor) type 295 | { 296 | case (0): // uptime 297 | if (mes.cmd == 1) send0 = true; 298 | break; 299 | case (1): // polling interval in seconds 300 | if (mes.cmd == 0) { // cmd == 0 means write a value 301 | TXinterval = mes.intVal; // change interval to radio packet value 302 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 303 | if (setAck) send1 = true; // send message if required 304 | #ifdef DEBUG 305 | Serial.print("Setting interval to "); 306 | Serial.print(TXinterval); 307 | Serial.println(" seconds"); 308 | #endif 309 | } 310 | else send1 = true; // cmd == 1 is a read request, so send polling interval 311 | break; 312 | case (2): // signal strength 313 | if (mes.cmd == 1) send2 = true; 314 | break; 315 | case (3): // software version 316 | if (mes.cmd == 1) send3 = true; 317 | break; 318 | case (4): // battery level 319 | if (mes.cmd == 1) send4 = true; 320 | break; 321 | case (5): // set ack status 322 | if (mes.cmd == 0) { 323 | if (mes.intVal == 0) setAck = false; 324 | if (mes.intVal == 1) setAck = true; 325 | if (setAck) send5 = true; // acknowledge message ? 326 | } 327 | else send5 = true; // read request means schedule a message 328 | break; 329 | 330 | default: send92 = true; // no valid device parsed 331 | } 332 | } // end parseCmd 333 | 334 | // 335 | // 336 | //====================== SENDMSG: sends messages that are flagged for transmission 337 | // 338 | 339 | void sendMsg() { // prepares values to be transmitted 340 | bool tx = false; // transmission flag 341 | mes.nodeID=NODEID; 342 | mes.intVal = 0; 343 | mes.fltVal = 0; 344 | mes.cmd = 0; // '0' means no action needed in gateway 345 | int i; 346 | for ( i = 0; i < sizeof(VERSION); i++){ 347 | mes.payLoad[i] = VERSION[i]; } 348 | mes.payLoad[i] = '\0'; // software version in payload string 349 | 350 | if (wakeUp) { // send wakeUp call 351 | mes.devID = 99; 352 | wakeUp = false; // reset transmission flag for this message 353 | txRadio(); // transmit 354 | } 355 | if (send0) { 356 | mes.devID = 0; 357 | mes.intVal = upTime; // minutes uptime 358 | send0 = false; 359 | txRadio(); 360 | } 361 | if (send1) { // transmission interval 362 | mes.devID = 1; 363 | mes.intVal = TXinterval; // seconds (integer) 364 | send1 = false; 365 | txRadio(); 366 | } 367 | if (send2) { 368 | mes.devID = 2; 369 | mes.intVal = signalStrength; // signal strength (integer) 370 | send2 = false; 371 | txRadio(); 372 | } 373 | if (send3) { // node software version (string) 374 | mes.devID = 3; // already stored in payload string 375 | send3 = false; 376 | txRadio(); 377 | } 378 | if (send4) { // measure voltage.. 379 | mes.devID = 4; 380 | long result; // Read 1.1V reference against AVcc 381 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 382 | delay(2); // Wait for Vref to settle 383 | ADCSRA |= _BV(ADSC); // Convert 384 | while (bit_is_set(ADCSRA,ADSC)); 385 | result = ADCL; 386 | result |= ADCH<<8; 387 | result = 1126400L / result; // Back-calculate in mV 388 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 389 | txRadio(); 390 | send4 = false; 391 | } 392 | if (send5) { // Acknowledge on 'SET' 393 | mes.devID = 5; 394 | if (setAck) mes.intVal = 1; else mes.intVal = 0;// state (integer) 395 | send5 = false; 396 | txRadio(); 397 | } 398 | 399 | 400 | if (cardDetect) { // RFID card detected 401 | mes.devID = 72; 402 | RFID_Code=""; 403 | for ( i = 0; i < 4; i++){ // fill string with 4 Hex numbers 404 | RFID_Code += String(UID[i],HEX); 405 | } 406 | RFID_Code.toUpperCase(); 407 | for (i= 0; i<9 ; i++){ // copy string (6 characters) to payload 408 | mes.payLoad[i] = RFID_Code[i]; 409 | } 410 | cardDetect = false; 411 | txRadio(); 412 | } 413 | if (send92) { // error message invalid device 414 | mes.intVal = mes.devID; 415 | mes.devID = 92; 416 | send92 = false; 417 | txRadio(); 418 | } 419 | 420 | } 421 | // 422 | // 423 | //======================= TXRADIO 424 | // 425 | 426 | void txRadio() // Transmits the 'mes'-struct to the gateway 427 | { 428 | cli(); 429 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes))) 430 | #ifdef DEBUG 431 | {Serial.print(" message "); 432 | Serial.print(mes.devID); 433 | Serial.println(" sent...");} 434 | else Serial.println("No connection...") 435 | #endif 436 | ; 437 | sei();} // end txRadio 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | -------------------------------------------------------------------------------- /RFID end node/readme.txt: -------------------------------------------------------------------------------- 1 | RFM69 RFID node sketch 2 | 3 | Version 2.0 4 | 5 | Lewishollow had a look at this code and proposed blocking interrupts at sketch level, rather than in the libraries. 6 | The code is now stable; RFID cards are being reported reliably and the code doesn't crash any more. 7 | 8 | Sending READ commands to the node is still not perfect: the blocking of interrupts sometimes causes radio packets to get lost. 9 | The gateway interprets this as a loss of signal of the radiolink. 10 | 11 | The unedited version of the MFRC522 library can be used. 12 | 13 | 14 | 15 | Version 1.0 16 | 17 | This node talks to the MQTT-Gateway and will: 18 | - send sensor data periodically 19 | - detect and read RFID cards and send the UID to the MQTT broker; 20 | 21 | The node is stable when only reporting RFID UID codes and node-initiated data. 22 | The node is unstable when trying to read values from the broker. 23 | Somehow the handling of received radio packets interferes with RFID code. 24 | 25 | The MFRC522 library can be found at: https://github.com/miguelbalboa/rfid 26 | Make sure to change the library file MFRC522.cpp before compiling: 27 | 28 | - add "cli();" to every occurrence of "digitalWrite(_chipSelectPin,LOW)" 29 | - add "sei();" to every occurrence of "digitalWrite(_chipSelectPin,HIGH)" 30 | 31 | Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 and RFID-RC522. 32 | Power requirements dictate that a reparate 3.3 Volts regulator is used to power both RFM69 and RFID reader 33 | A RED led (D7) is used to indicate an RFID card has been detected and read. It will stay on during HOLDOFF msec. 34 | 35 | Whenever an RFID card is detected am MQTT message will be generated with topic: 36 | 37 | home/rfm_gw/nb/node05/dev72 38 | 39 | The messageblock will contain the detected RFID-UID in ASCII. 40 | -------------------------------------------------------------------------------- /Relay end node/Device/device.h: -------------------------------------------------------------------------------- 1 | #include "Arduino.h" 2 | 3 | typedef struct { // Radio packet format 4 | int nodeID; // node identifier 5 | int devID; // device identifier 6 | int cmd; // read or write 7 | long intVal; // integer payload 8 | float fltVal; // floating payload 9 | char payLoad[32]; // string payload 10 | } Message; 11 | 12 | class Device{ 13 | void (*readPointer)(Message *); 14 | void (*writePointer)(const Message *); 15 | public: 16 | const int id; 17 | bool setTX; 18 | Device (int x, bool tx) : id(x), setTX(tx) { readPointer = &dummyRead; writePointer = &dummyWrite; } 19 | Device (int x, bool tx, void (*ptr)(Message *)) : id(x), setTX(tx), readPointer(ptr) { writePointer = &dummyWrite; } 20 | Device (int x, bool tx, void (*ptr)(Message *), void (*ptr2)(const Message *)) : id(x), setTX(tx), readPointer(ptr), writePointer(ptr2) {} 21 | void read(Message *mess) { readPointer(mess);} 22 | void write(const Message *mess) { writePointer(mess);} 23 | static void dummyRead(Message *mess) {} 24 | static void dummyWrite(const Message *mess) {} 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /Relay end node/README.md: -------------------------------------------------------------------------------- 1 | This is a relay end node designed to be used as a remote power strip. 2 | 3 | A device class is provided to allow more flexibility in creating future devices. 4 | The device folder needs to be moved into your arduino library folder. 5 | All that's required is any normal setup for the device (pinMode, i2c, spi, etc) and creating a read and write function. 6 | To register the new device create an instance of it like this: 7 | 8 | Device devicename(deviceID, check_periodically?, read_function, write_function(optional)); 9 | 10 | Then add it to the array of devices. All messages will be parsed automatically. 11 | 12 | The node also tries to conserve power by sleeping when not actively doing anything. 13 | If the node is passively sending data, and does not need to be polled, you can save more power by shutting down the radio between broadcasts. 14 | -------------------------------------------------------------------------------- /Relay end node/relay.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /************************************** 8 | CONFIGURATION PARAMETERS 9 | **************************************/ 10 | 11 | #define NODEID 2 // unique node ID within the closed network 12 | #define GATEWAYID 1 // node ID of the Gateway is always 1 13 | #define NETWORKID 1 // network ID of the network 14 | #define ENCRYPTKEY "1234567891011121" // 16-char encryption key; same as on Gateway! 15 | #define DEBUG // uncomment for debugging 16 | #define VERSION "RELAY V1.0" // this value can be queried as device 3 17 | #define SERIAL_BAUD 9600 18 | 19 | /************************************** 20 | Wireless settings 21 | Match frequency to the hardware version of the radio 22 | **************************************/ 23 | 24 | //#define FREQUENCY RF69_433MHZ 25 | //#define FREQUENCY RF69_868MHZ 26 | #define FREQUENCY RF69_915MHZ 27 | 28 | #define IS_RFM69HW // uncomment only for RFM69HW! 29 | #define PROMISCUOUS_MODE false 30 | #define ACK_TIME 30 // max # of ms to wait for an ack 31 | #define RETRIES 5 //number of tx retries 32 | 33 | /************************************** 34 | device settings 35 | **************************************/ 36 | 37 | #define BTN_INT 1 //interrupt number 38 | #define BTN_PIN 3 //button pin 39 | #define RELAY 9 //relay pin 40 | 41 | /************************************** 42 | global variables 43 | **************************************/ 44 | int TXinterval = 20; // periodic transmission interval in seconds 45 | bool setACK = false; // send ACK message on 'SET' request 46 | bool toggle = true; 47 | bool updatesSent = false; 48 | 49 | volatile bool btnPressed = false; 50 | volatile long lastBtnPress = -1; // timestamp last buttonpress 51 | volatile long wdtCounter = 0; 52 | 53 | const Message DEFAULT_MSG = {NODEID, 0, 0, 0, 0, VERSION}; 54 | 55 | /************************************** 56 | configure devices 57 | **************************************/ 58 | 59 | //Device name(devID, tx_periodically, read_function, optional_write_function) 60 | 61 | Device uptimeDev(0, false, readUptime); 62 | Device txIntDev(1, false, readTXInt, writeTXInt); 63 | Device rssiDev(2, false, readRSSI); 64 | Device verDev(3, false); 65 | Device voltDev(4, false, readVoltage); 66 | Device ackDev(5, false, readACK, writeACK); 67 | Device toggleDev(6, false, readToggle, writeToggle); 68 | Device relayDev(17, false, readRelay, writeRelay); 69 | 70 | static Device devices[] = {uptimeDev, txIntDev, rssiDev, verDev, 71 | voltDev, ackDev, toggleDev, relayDev}; 72 | 73 | RFM69 radio; 74 | 75 | /******************************************* 76 | put non-system read/write functions here 77 | ********************************************/ 78 | 79 | void readRelay(Message *mess){ 80 | digitalRead(RELAY) ? mess->intVal = 1 : mess->intVal = 0; 81 | } 82 | 83 | void writeRelay(const Message *mess){ 84 | digitalWrite(RELAY, mess->intVal); 85 | } 86 | 87 | /********************************************* 88 | Setup 89 | *********************************************/ 90 | 91 | void setup() { 92 | //disable watchdog timer during setup 93 | wdt_disable(); 94 | 95 | //set all pins as input with pullups, floating pins can waste power 96 | DDRD &= B00000011; // set Arduino pins 2 to 7 as inputs, leaves 0 & 1 (RX & TX) as is 97 | DDRB = B00000000; // set pins 8 to 13 as inputs 98 | PORTD |= B11111100; // enable pullups on pins 2 to 7, leave pins 0 and 1 alone 99 | PORTB |= B11111111; // enable pullups on pins 8 to 13 100 | 101 | //if debug enabled, initialize serial 102 | #ifdef DEBUG 103 | Serial.begin(SERIAL_BAUD); 104 | Serial.println("Serial initialized"); 105 | #endif 106 | 107 | //initialize IO 108 | pinMode(BTN_PIN, INPUT_PULLUP); 109 | pinMode(RELAY, OUTPUT); 110 | digitalWrite(RELAY, LOW); 111 | 112 | //initialize radio 113 | radio.initialize(FREQUENCY,NODEID,NETWORKID); 114 | radio.rcCalibration(); 115 | #ifdef IS_RFM69HW 116 | radio.setHighPower(); // only for RFM69HW! 117 | #endif 118 | radio.encrypt(ENCRYPTKEY); // set radio encryption 119 | radio.promiscuous(PROMISCUOUS_MODE); // only listen to closed network 120 | 121 | #ifdef DEBUG 122 | Serial.print("Node Software Version "); 123 | Serial.println(VERSION); 124 | Serial.print("\nTransmitting at "); 125 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 126 | Serial.println(" Mhz..."); 127 | #endif 128 | 129 | //configure watchdog as 1s counter for uptime and to wake from sleep 130 | watchdogSetup(); 131 | 132 | //setup interrupt for button 133 | attachInterrupt(BTN_INT, buttonHandler, LOW); 134 | 135 | //send wakeup message 136 | Message wakeup = DEFAULT_MSG; 137 | wakeup.devID = 99; 138 | txRadio(&wakeup); 139 | } 140 | 141 | void loop() { 142 | Message reply = DEFAULT_MSG; 143 | 144 | if (radio.receiveDone()){ 145 | if (radio.DATALEN != sizeof(Message)){ 146 | Serial.println("INVALID PACKET"); 147 | }else{ 148 | Message mess = *(Message*)radio.DATA; 149 | if (radio.ACKRequested()){ 150 | Serial.println("sending ack"); 151 | radio.sendACK(); 152 | }else{ 153 | Serial.println("ack not requested"); 154 | } 155 | bool match = false; 156 | 157 | //check if message is for any devices registered on node 158 | for (int i = 0; i < sizeof(devices) / sizeof(Device); i++){ 159 | if (mess.devID == devices[i].id){ 160 | match = true; 161 | reply.devID = devices[i].id; 162 | //write for cmd 0 163 | if (mess.cmd == 0){ 164 | devices[i].write(&mess); 165 | #ifdef DEBUG 166 | Serial.print("writing node "); 167 | Serial.print(mess.nodeID); 168 | Serial.print(" dev "); 169 | Serial.println(mess.devID); 170 | #endif 171 | if (setACK){ 172 | Serial.println(reply.devID); 173 | devices[i].read(&reply); 174 | txRadio(&reply); 175 | } 176 | //read for cmd 1 177 | }else if (mess.cmd == 1){ 178 | devices[i].read(&reply); 179 | #ifdef DEBUG 180 | Serial.print("reading node "); 181 | Serial.print(reply.nodeID); 182 | Serial.print(" dev "); 183 | Serial.println(reply.devID); 184 | #endif 185 | txRadio(&reply); 186 | } 187 | } 188 | } 189 | //invalid device id in message 190 | if (!match){ 191 | reply.devID = 92; 192 | txRadio(&reply); 193 | } 194 | } 195 | } 196 | 197 | //check if any devices needs to transmit periodic info 198 | if (!updatesSent && wdtCounter % TXinterval == 0){ 199 | Serial.println("Sending periodic updates"); 200 | for (int i = 0; i <= sizeof(devices) / sizeof(Device); i++){ 201 | if (devices[i].setTX){ 202 | reply = DEFAULT_MSG; 203 | reply.devID = devices[i].id; 204 | devices[i].read(&reply); 205 | txRadio(&reply); 206 | } 207 | } 208 | updatesSent = true; 209 | }else if(wdtCounter % TXinterval != 0){ 210 | updatesSent = false; 211 | } 212 | 213 | //if button was pressed and enabled toggle the relay 214 | if (btnPressed && toggle){ 215 | digitalWrite(RELAY, !digitalRead(RELAY)); 216 | reply = DEFAULT_MSG; 217 | reply.devID = 17; 218 | relayDev.read(&reply); 219 | txRadio(&reply); 220 | } 221 | btnPressed = false; 222 | 223 | //Disabling sleep for now, was making comms too unreliable 224 | /*#ifdef DEBUG 225 | //make sure serial tx is done before sleeping 226 | Serial.flush(); 227 | while ((UCSR0A & _BV (TXC0)) == 0){} 228 | #endif 229 | */ 230 | 231 | //put chip to sleep until button is pressed, packet is RX, or watchdog timer fires 232 | //sleep(); 233 | } 234 | 235 | void txRadio(Message * mess){ 236 | Serial.print(" message "); 237 | Serial.print(mess->devID); 238 | Serial.println(" sent..."); 239 | if (!radio.sendWithRetry(GATEWAYID, mess, sizeof(*mess), RETRIES, ACK_TIME)){ 240 | Serial.println("No connection..."); 241 | } 242 | } 243 | 244 | void readUptime(Message *mess){ 245 | mess->intVal = wdtCounter / 60; 246 | } 247 | 248 | void readTXInt(Message *mess){ 249 | mess->intVal = TXinterval; 250 | } 251 | 252 | void writeTXInt(const Message *mess){ 253 | TXinterval = mess->intVal; 254 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 255 | } 256 | 257 | void readRSSI(Message *mess){ 258 | mess->intVal = radio.RSSI; 259 | } 260 | 261 | void readVoltage(Message *mess){ 262 | long result; // Read 1.1V reference against AVcc 263 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 264 | delay(2); // Wait for Vref to settle 265 | ADCSRA |= _BV(ADSC); // Convert 266 | while (bit_is_set(ADCSRA,ADSC)); 267 | result = ADCL; 268 | result |= ADCH<<8; 269 | result = 1126400L / result; // Back-calculate in mV 270 | mess->fltVal = float(result/1000.0); // Voltage in Volt (float) 271 | } 272 | 273 | void readACK(Message *mess){ 274 | setACK ? mess->intVal = 1 : mess->intVal = 0; 275 | } 276 | 277 | void writeACK(const Message *mess){ 278 | mess->intVal ? setACK = true: setACK = false; 279 | } 280 | 281 | void readToggle(Message *mess){ 282 | toggle ? mess->intVal = 1 : mess->intVal = 0; 283 | } 284 | 285 | void writeToggle(const Message *mess){ 286 | mess->intVal ? toggle = true: toggle = false; 287 | } 288 | 289 | void sleep(){ 290 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); 291 | sleep_enable(); 292 | sleep_bod_disable(); 293 | sleep_mode(); 294 | sleep_disable(); 295 | } 296 | 297 | void watchdogSetup(void){ 298 | cli(); 299 | wdt_reset(); 300 | WDTCSR |=(1< 45 | #include 46 | #include 47 | 48 | // 49 | // CONFIGURATION PARAMETERS 50 | // 51 | #define NODEID 4 // unique node ID within the closed network 52 | #define GATEWAYID 1 // node ID of the Gateway is always 1 53 | #define NETWORKID 100 // network ID of the network 54 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 55 | #define DEBUG // uncomment for debugging 56 | #define VERSION "RC V1.0" // this value can be queried as device 3 57 | 58 | // Wireless settings Match frequency to the hardware version of the radio 59 | 60 | //#define FREQUENCY RF69_433MHZ 61 | #define FREQUENCY RF69_868MHZ 62 | //#define FREQUENCY RF69_915MHZ 63 | 64 | #define IS_RFM69HW // uncomment only for RFM69HW! 65 | #define ACK_TIME 50 // max # of ms to wait for an ack 66 | 67 | #define TXDATA 3 // Transmitter pin 68 | #define SERIAL_BAUD 115200 69 | #define HOLDOFF 10000 // blocking period between button messages 70 | 71 | // 72 | // STARTUP DEFAULTS 73 | // 74 | long TXinterval = 20; // periodic transmission interval in seconds 75 | long TIMinterval = 20; // timer interval in seconds 76 | bool ackButton = false; // flag for message on button press 77 | bool toggleOnButton = true; // toggle output on button press 78 | 79 | // 80 | // VARIABLES 81 | // 82 | long lastPeriod = -1; // timestamp last transmission 83 | long lastBtnPress = -1; // timestamp last buttonpress 84 | long lastMinute = -1; // timestamp last minute 85 | long upTime = 0; // uptime in minutes 86 | int signalStrength; // radio signal strength 87 | bool setAck = true; // send ACK message on 'SET' request 88 | bool send0, send1, send2, send3, send4; 89 | bool send5, send72, send92; // message triggers 90 | bool promiscuousMode = false; // only listen to nodes within the closed network 91 | bool curState = true; // current button state 92 | bool lastState = true; // last button state 93 | bool wakeUp = true; // wakeup flag 94 | bool msgBlock = false; // flag to hold button messages to prevent overload 95 | char KKgroup; // Group of the targeted KAKU device 96 | int KKnum; // Code of the targeted KAKU device 97 | bool error; // error flag 98 | 99 | typedef struct { // Radio packet format 100 | int nodeID; // node identifier 101 | int devID; // device identifier 102 | int cmd; // read or write 103 | long intVal; // integer payload 104 | float fltVal; // floating payload 105 | char payLoad[32]; // string payload 106 | } Message; 107 | 108 | Message mes; 109 | 110 | KaKuTransmitter kakuTx(TXDATA); // KaKu transmitter on pin TXDATA 111 | RFM69 radio; 112 | 113 | // 114 | //===================== SETUP ======================================== 115 | // 116 | void setup() { 117 | #ifdef DEBUG 118 | Serial.begin(SERIAL_BAUD); 119 | #endif 120 | 121 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 122 | #ifdef IS_RFM69HW 123 | radio.setHighPower(); // only for RFM69HW! 124 | #endif 125 | radio.encrypt(ENCRYPTKEY); // set radio encryption 126 | radio.promiscuous(promiscuousMode); // only listen to closed network 127 | wakeUp = true; // send wakeup message 128 | 129 | #ifdef DEBUG 130 | Serial.print("Node Software Version "); 131 | Serial.println(VERSION); 132 | Serial.print("\nTransmitting at "); 133 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 134 | Serial.println(" Mhz..."); 135 | #endif 136 | } // end setup 137 | 138 | // 139 | // 140 | //==================== MAIN ======================================== 141 | // 142 | void loop() { 143 | // RECEIVE radio input 144 | // 145 | if (receiveData()) parseCmd(); // receive and parse any radio input 146 | 147 | 148 | // UPTIME 149 | // 150 | 151 | if (lastMinute != (millis()/60000)) { // another minute passed ? 152 | lastMinute = millis()/60000; 153 | upTime++; 154 | } 155 | 156 | // PERIODIC TRANSMISSION 157 | // 158 | 159 | if (TXinterval > 0) 160 | { 161 | int currPeriod = millis()/(TXinterval*1000); 162 | if (currPeriod != lastPeriod) { // interval elapsed ? 163 | lastPeriod = currPeriod; 164 | 165 | // list of sensordata to be sent periodically.. 166 | // remove comment to include parameter in transmission 167 | 168 | // send1 = true; // send transmission interval 169 | // send2 = true; // signal strength 170 | // send4 = true; // voltage level 171 | 172 | } 173 | } 174 | 175 | // SEND RADIO PACKETS 176 | // 177 | 178 | sendMsg(); // send any radio messages 179 | 180 | } // end loop 181 | 182 | // 183 | // 184 | //===================== FUNCTIONS ========================================== 185 | 186 | // 187 | //======== RECEIVEDATA : receive data from gateway over radio 188 | // 189 | 190 | bool receiveData() { 191 | bool validPacket = false; 192 | if (radio.receiveDone()) // check for received packets 193 | { 194 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 195 | #ifdef DEBUG 196 | Serial.println("invalid message structure..") 197 | #endif 198 | ; 199 | else 200 | { 201 | mes = *(Message*)radio.DATA; 202 | validPacket = true; // YES, we have a packet ! 203 | signalStrength = radio.RSSI; 204 | #ifdef DEBUG 205 | Serial.print(mes.devID); 206 | Serial.print(", "); 207 | Serial.print(mes.cmd); 208 | Serial.print(", "); 209 | Serial.print(mes.intVal); 210 | Serial.print(", "); 211 | Serial.print(mes.fltVal); 212 | Serial.print(", RSSI= "); 213 | Serial.println(radio.RSSI); 214 | Serial.print("Node: "); 215 | Serial.println(mes.nodeID); 216 | for (int i=0; i=0 && KKgroup - 'A' < 16) && 296 | (KKnum >=0 && KKnum <=9)) { 297 | if (txtLine.substring(8) == "ON") kakuTx.sendSignal(KKgroup, KKnum, true); 298 | if (txtLine.substring(8) == "OFF") kakuTx.sendSignal(KKgroup, KKnum, false); 299 | if (!(txtLine.substring(8) == "ON" || txtLine.substring(8) == "OFF")) error = true; 300 | } else error = true; 301 | } else error = true; 302 | 303 | 304 | if (error || setAck) send72 = true; // acknowledge message ? 305 | } 306 | break; 307 | default: send92 = true; // no valid device parsed 308 | } 309 | } // end parseCmd 310 | 311 | // 312 | // 313 | //====================== SENDMSG: sends messages that are flagged for transmission 314 | // 315 | 316 | void sendMsg() { // prepares values to be transmitted 317 | bool tx = false; // transmission flag 318 | mes.nodeID=NODEID; 319 | mes.intVal = 0; 320 | mes.fltVal = 0; 321 | mes.cmd = 0; // '0' means no action needed in gateway 322 | int i; 323 | for ( i = 0; i < sizeof(VERSION); i++){ 324 | mes.payLoad[i] = VERSION[i]; } 325 | mes.payLoad[i] = '\0'; // software version in payload string 326 | 327 | if (wakeUp) { // send wakeUp call 328 | mes.devID = 99; 329 | wakeUp = false; // reset transmission flag for this message 330 | txRadio(); // transmit 331 | } 332 | if (send0) { 333 | mes.devID = 0; 334 | mes.intVal = upTime; // minutes uptime 335 | send0 = false; 336 | txRadio(); 337 | } 338 | if (send1) { // transmission interval 339 | mes.devID = 1; 340 | mes.intVal = TXinterval; // seconds (integer) 341 | send1 = false; 342 | txRadio(); 343 | } 344 | if (send2) { 345 | mes.devID = 2; 346 | mes.intVal = signalStrength; // signal strength (integer) 347 | send2 = false; 348 | txRadio(); 349 | } 350 | if (send3) { // node software version (string) 351 | mes.devID = 3; // already stored in payload string 352 | send3 = false; 353 | txRadio(); 354 | } 355 | if (send4) { // measure voltage.. 356 | mes.devID = 4; 357 | long result; // Read 1.1V reference against AVcc 358 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 359 | delay(2); // Wait for Vref to settle 360 | ADCSRA |= _BV(ADSC); // Convert 361 | while (bit_is_set(ADCSRA,ADSC)); 362 | result = ADCL; 363 | result |= ADCH<<8; 364 | result = 1126400L / result; // Back-calculate in mV 365 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 366 | txRadio(); 367 | send4 = false; 368 | } 369 | if (send5) { // Acknowledge on 'SET' 370 | mes.devID = 5; 371 | if (setAck) mes.intVal = 1; else mes.intVal = 0; // state (integer) 372 | send5 = false; 373 | txRadio(); 374 | } 375 | 376 | if (send72) { 377 | mes.devID = 72; 378 | mes.intVal = 1; 379 | if (error) sprintf(mes.payLoad, "KAKU syntax error"); 380 | else sprintf(mes.payLoad, "command received"); 381 | send72 = false; 382 | txRadio(); 383 | } 384 | if (send92) { // error message invalid device 385 | mes.intVal = mes.devID; 386 | mes.devID = 92; 387 | send92 = false; 388 | txRadio(); 389 | } 390 | 391 | } 392 | // 393 | // 394 | //======================= TXRADIO 395 | // 396 | 397 | void txRadio() // Transmits the 'mes'-struct to the gateway 398 | { 399 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes))) 400 | #ifdef DEBUG 401 | {Serial.print(" message "); 402 | Serial.print(mes.devID); 403 | Serial.println(" sent...");} 404 | else Serial.println("No connection...") 405 | #endif 406 | ;} // end txRadio 407 | 408 | 409 | 410 | 411 | 412 | 413 | -------------------------------------------------------------------------------- /Remote Control node/RFM_RC_node_20.ino: -------------------------------------------------------------------------------- 1 | // RFM69 RC node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will send out commands to RC-controlled mains switches. 4 | // I use devices of brand KlikAanKlikUit. The library used supports other European brands. 5 | // 6 | // 7 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 8 | // 9 | // A 433 MHZ transmitter is used to send out commands in the appropriate format. 10 | // The RemoteSwitch library by Randy Simons is used 11 | // Get this library at : https://bitbucket.org/fuzzillogic 12 | // Commands are sent as a string and have the following format: 13 | // KuKa XY ON of KuKa XY OFF where XY is the device address of the switch. 14 | // 15 | // Defined devices for this node are: 16 | // 17 | // 0 uptime: read uptime node in minutes 18 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 19 | // 2 RSSI: read radio signal strength 20 | // 3 Version: read version node software 21 | // 4 voltage: read battery level 22 | // 5 ACK: read/set acknowledge message after a 'set' request 23 | // 9 retry: read number of retransmissions needed in radiolink 24 | // 72 command: the command is sent as a string 25 | // 90 error: tx only: error message if no wireless connection (generated by gateway) 26 | // 92 error: tx only: device not supported 27 | // 99 wakeup: tx only: first message sent on node startup 28 | // 29 | // The RFM69 is connected to the following pins: 30 | // - D13 SCK 31 | // - D12 MISO 32 | // - D11 MOSI 33 | // - D10 SS 34 | // - D2 DIO0 35 | // 36 | // The 433 Mhz transmitter is connected to pin D3, GND and +5 Volt. 37 | // 38 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 39 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 40 | // 41 | // version 1.0 by Computourist@gmail.com Feb 2015 42 | // version 2.0 fixed bug in function TXradio that prevented retransmission of radio packets ; oct 2015 43 | // 44 | 45 | #include 46 | #include 47 | #include 48 | 49 | // 50 | // CONFIGURATION PARAMETERS 51 | // 52 | #define NODEID 4 // unique node ID within the closed network 53 | #define GATEWAYID 1 // node ID of the Gateway is always 1 54 | #define NETWORKID 100 // network ID of the network 55 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 56 | #define DEBUG // uncomment for debugging 57 | #define VERSION "RC V1.0" // this value can be queried as device 3 58 | 59 | // Wireless settings Match frequency to the hardware version of the radio 60 | 61 | //#define FREQUENCY RF69_433MHZ 62 | #define FREQUENCY RF69_868MHZ 63 | //#define FREQUENCY RF69_915MHZ 64 | 65 | #define IS_RFM69HW // uncomment only for RFM69HW! 66 | #define ACK_TIME 50 // max # of ms to wait for an ack 67 | 68 | #define TXDATA 9 // Transmitter pin 69 | #define SERIAL_BAUD 115200 70 | #define HOLDOFF 10000 // blocking period between button messages 71 | 72 | // 73 | // STARTUP DEFAULTS 74 | // 75 | long TXinterval = 120; // periodic transmission interval in seconds 76 | long TIMinterval = 20; // timer interval in seconds 77 | bool ackButton = false; // flag for message on button press 78 | bool toggleOnButton = true; // toggle output on button press 79 | 80 | // 81 | // VARIABLES 82 | // 83 | long lastPeriod = -1; // timestamp last transmission 84 | long lastBtnPress = -1; // timestamp last buttonpress 85 | long lastMinute = -1; // timestamp last minute 86 | long upTime = 0; // uptime in minutes 87 | int signalStrength; // radio signal strength 88 | bool setAck = true; // send ACK message on 'SET' request 89 | bool send0, send1, send2, send3, send4; 90 | bool send5, send9, send72, send92; // message triggers 91 | bool promiscuousMode = false; // only listen to nodes within the closed network 92 | bool curState = true; // current button state 93 | bool lastState = true; // last button state 94 | bool wakeUp = true; // wakeup flag 95 | bool msgBlock = false; // flag to hold button messages to prevent overload 96 | char KKgroup; // Group of the targeted KAKU device 97 | int KKnum; // Code of the targeted KAKU device 98 | bool error; // error flag 99 | bool retx = true; // flag to signal retransmission 100 | int numtx; // number of retransmissions 101 | 102 | typedef struct { // Radio packet format 103 | int nodeID; // node identifier 104 | int devID; // device identifier 105 | int cmd; // read or write 106 | long intVal; // integer payload 107 | float fltVal; // floating payload 108 | char payLoad[32]; // string payload 109 | } Message; 110 | 111 | Message mes; 112 | 113 | KaKuTransmitter kakuTx(TXDATA); // KaKu transmitter on pin TXDATA 114 | RFM69 radio; 115 | 116 | // 117 | //===================== SETUP ======================================== 118 | // 119 | void setup() { 120 | #ifdef DEBUG 121 | Serial.begin(SERIAL_BAUD); 122 | #endif 123 | 124 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 125 | #ifdef IS_RFM69HW 126 | radio.setHighPower(); // only for RFM69HW! 127 | #endif 128 | radio.encrypt(ENCRYPTKEY); // set radio encryption 129 | radio.promiscuous(promiscuousMode); // only listen to closed network 130 | wakeUp = true; // send wakeup message 131 | 132 | #ifdef DEBUG 133 | Serial.print("Node Software Version "); 134 | Serial.println(VERSION); 135 | Serial.print("\nTransmitting at "); 136 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 137 | Serial.println(" Mhz..."); 138 | #endif 139 | } // end setup 140 | 141 | // 142 | // 143 | //==================== MAIN ======================================== 144 | // 145 | void loop() { 146 | // RECEIVE radio input 147 | // 148 | if (receiveData()) parseCmd(); // receive and parse any radio input 149 | 150 | 151 | // UPTIME 152 | // 153 | 154 | if (lastMinute != (millis()/60000)) { // another minute passed ? 155 | lastMinute = millis()/60000; 156 | upTime++; 157 | } 158 | 159 | // PERIODIC TRANSMISSION 160 | // 161 | 162 | if (TXinterval > 0) 163 | { 164 | int currPeriod = millis()/(TXinterval*1000); 165 | if (currPeriod != lastPeriod) { // interval elapsed ? 166 | lastPeriod = currPeriod; 167 | 168 | // list of sensordata to be sent periodically.. 169 | // remove comment to include parameter in transmission 170 | 171 | // send1 = true; // send transmission interval 172 | send2 = true; // signal strength 173 | // send4 = true; // voltage level 174 | // send9 = true; // number of retransmissions 175 | 176 | } 177 | } 178 | 179 | // SEND RADIO PACKETS 180 | // 181 | 182 | sendMsg(); // send any radio messages 183 | 184 | } // end loop 185 | 186 | // 187 | // 188 | //===================== FUNCTIONS ========================================== 189 | 190 | // 191 | //======== RECEIVEDATA : receive data from gateway over radio 192 | // 193 | 194 | bool receiveData() { 195 | bool validPacket = false; 196 | if (radio.receiveDone()) // check for received packets 197 | { 198 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 199 | #ifdef DEBUG 200 | Serial.println("invalid message structure..") 201 | #endif 202 | ; 203 | else 204 | { 205 | mes = *(Message*)radio.DATA; 206 | validPacket = true; // YES, we have a packet ! 207 | signalStrength = radio.RSSI; 208 | #ifdef DEBUG 209 | Serial.print(mes.devID); 210 | Serial.print(", "); 211 | Serial.print(mes.cmd); 212 | Serial.print(", "); 213 | Serial.print(mes.intVal); 214 | Serial.print(", "); 215 | Serial.print(mes.fltVal); 216 | Serial.print(", RSSI= "); 217 | Serial.println(radio.RSSI); 218 | Serial.print("Node: "); 219 | Serial.println(mes.nodeID); 220 | for (int i=0; i=0 && KKgroup - 'A' < 16) && 304 | (KKnum >=0 && KKnum <=9)) { 305 | if (txtLine.substring(8) == "ON") kakuTx.sendSignal(KKgroup, KKnum, true); 306 | if (txtLine.substring(8) == "OFF") kakuTx.sendSignal(KKgroup, KKnum, false); 307 | if (!(txtLine.substring(8) == "ON" || txtLine.substring(8) == "OFF")) error = true; 308 | } else error = true; 309 | } else error = true; 310 | 311 | 312 | if (error || setAck) send72 = true; // acknowledge message ? 313 | } 314 | break; 315 | default: send92 = true; // no valid device parsed 316 | } 317 | } // end parseCmd 318 | 319 | // 320 | // 321 | //====================== SENDMSG: sends messages that are flagged for transmission 322 | // 323 | 324 | void sendMsg() { // prepares values to be transmitted 325 | bool tx = false; // transmission flag 326 | mes.nodeID=NODEID; 327 | mes.intVal = 0; 328 | mes.fltVal = 0; 329 | mes.cmd = 0; // '0' means no action needed in gateway 330 | int i; 331 | for ( i = 0; i < sizeof(VERSION); i++){ 332 | mes.payLoad[i] = VERSION[i]; } 333 | mes.payLoad[i] = '\0'; // software version in payload string 334 | 335 | if (wakeUp) { // send wakeUp call 336 | mes.devID = 99; 337 | wakeUp = false; // reset transmission flag for this message 338 | txRadio(); // transmit 339 | } 340 | if (send0) { 341 | mes.devID = 0; 342 | mes.intVal = upTime; // minutes uptime 343 | send0 = false; 344 | txRadio(); 345 | } 346 | if (send1) { // transmission interval 347 | mes.devID = 1; 348 | mes.intVal = TXinterval; // seconds (integer) 349 | send1 = false; 350 | txRadio(); 351 | } 352 | if (send2) { 353 | mes.devID = 2; 354 | mes.intVal = signalStrength; // signal strength (integer) 355 | send2 = false; 356 | txRadio(); 357 | } 358 | if (send3) { // node software version (string) 359 | mes.devID = 3; // already stored in payload string 360 | send3 = false; 361 | txRadio(); 362 | } 363 | if (send4) { // measure voltage.. 364 | mes.devID = 4; 365 | long result; // Read 1.1V reference against AVcc 366 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 367 | delay(2); // Wait for Vref to settle 368 | ADCSRA |= _BV(ADSC); // Convert 369 | while (bit_is_set(ADCSRA,ADSC)); 370 | result = ADCL; 371 | result |= ADCH<<8; 372 | result = 1126400L / result; // Back-calculate in mV 373 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 374 | txRadio(); 375 | send4 = false; 376 | } 377 | if (send5) { // Acknowledge on 'SET' 378 | mes.devID = 5; 379 | if (setAck) mes.intVal = 1; else mes.intVal = 0; // state (integer) 380 | send5 = false; 381 | txRadio(); 382 | } 383 | if (send9) { // number of retransmissions 384 | mes.devID = 9; 385 | mes.intVal = numtx; // number (integer) 386 | send9 = false; 387 | txRadio(); 388 | } 389 | if (send72) { 390 | mes.devID = 72; 391 | mes.intVal = 1; 392 | if (error) sprintf(mes.payLoad, "KAKU syntax error"); 393 | else sprintf(mes.payLoad, "command received"); 394 | send72 = false; 395 | txRadio(); 396 | } 397 | if (send92) { // error message invalid device 398 | mes.intVal = mes.devID; 399 | mes.devID = 92; 400 | send92 = false; 401 | txRadio(); 402 | } 403 | 404 | } 405 | // 406 | // 407 | //======================= TXRADIO 408 | // 409 | 410 | void txRadio() // Transmits the 'mes'-struct to the gateway 411 | { 412 | retx = true; 413 | int i = 0; 414 | 415 | while (retx && i<6) { 416 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes),5)) { 417 | retx = false; 418 | #ifdef DEBUG 419 | Serial.print(" message "); 420 | Serial.print(mes.devID); 421 | Serial.println(" sent..."); 422 | #endif 423 | } else delay(500); 424 | i++; 425 | } 426 | numtx = i; // store number of retransmissions needed 427 | #ifdef DEBUG 428 | if (retx) Serial.println("No connection...") 429 | #endif 430 | ;} // end txRadio 431 | 432 | 433 | 434 | 435 | 436 | 437 | -------------------------------------------------------------------------------- /Remote Control node/readme.txt: -------------------------------------------------------------------------------- 1 | RFM-MQTT-RC Release 2.0 2 | by Computourist@gmail.com Oct 2015 3 | 4 | Made this node compatible to gateway 2.3: 5 | - made changes in function TXradio to handle retransmissions. 6 | - added device 9 to expose the number of retransmission 7 | 8 | RFM69 RC node sketch 9 | 10 | This node talks to the MQTT-Gateway and will send out commands to RC-controlled mains switches. 11 | I use devices of brand KlikAanKlikUit. The library used supports other European brands. 12 | 13 | Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 14 | 15 | A 433 MHZ transmitter is used to send out commands in the appropriate format. 16 | 17 | Commands are sent as a string and have the following format: 18 | KuKa XY ON of KuKa XY OFF where XY is the device address of the switch. 19 | 20 | Example: 21 | 22 | topic: home/rfm_gw/sb/node04/dev72 with message: KAKU B1 ON will switch the device with code B1 On. 23 | 24 | The RemoteSwitch library by Randy Simons is used. 25 | Get this library at : https://bitbucket.org/fuzzillogic 26 | -------------------------------------------------------------------------------- /Version_1 Obsolete/Gateway/MQTT_gateway_schematic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Version_1 Obsolete/Gateway/MQTT_gateway_schematic.jpg -------------------------------------------------------------------------------- /Version_1 Obsolete/Node/RFM_DHT_NODE_17.ino: -------------------------------------------------------------------------------- 1 | // RFM69 DHT node sketch 2 | // 3 | // This node talks to the MQTT-Gateway and will: 4 | // - send sensor data periodically and on-demand 5 | // - receive commands from the gateway to control actuators 6 | // - receive commands from the gateway to change settings 7 | // 8 | // Several nodes can operate within a single network; each have a unique node ID. 9 | // On startup the node operates with default values, set on compilation. 10 | // 11 | // Hardware used is a 3.3 Volt 8MHz arduino Pro; this is easier to interface to RFM69 12 | // 13 | // A DHT-11 is used for temperature & humidity measurements, other sensors and outputs can be added easily. 14 | // 15 | // Message format is: nodeID/deviceID/command/integer/float/string 16 | // 17 | // Depending on the type of data (integer, float or string) one of the payload variables is used 18 | // Command = 0 means write a value in the node, cmd = 1 means read a value 19 | // 20 | // Current defined devices are: 21 | // 22 | // 0 error: tx only: error message if no wireless connection (generated by gateway) 23 | // 1 node: read/set transmission interval in seconds, 0 means no periodic transmission 24 | // 2 RSSI: read radio signal strength 25 | // 3 Version: read version node software 26 | // 4 voltage: read battery level 27 | // 5 ACK: read/set acknowledge message after a 'set' request 28 | // 6 toggle: read/set toggle function on button press 29 | // 7 timer: read/set activation timer after button press in seconds, 0 means no timer 30 | // 8 buttonpress: read/set flag to send a message when button pressed 31 | // 32 | // 10 actuator: read/set LED or relay output 33 | // 20 Button: tx only: message sent when button pressed 34 | // 31 temperature: read temperature 35 | // 32 humidity: read humidity 36 | // 99 wakeup: tx only: first message sent on node startup 37 | // 38 | // The button can be set to: 39 | // - generate a message on each press (limited to one per 10 seconds) and/or 40 | // - toggle the output ACT1 (local node function) or 41 | // - activate the output for a fixed time period (local node function) 42 | // 43 | // A debug mode is included which outputs messages on the serial output 44 | // 45 | // RFM69 Library by Felix Rusu - felix@lowpowerlab.com 46 | // Get the RFM69 library at: https://github.com/LowPowerLab/ 47 | // 48 | // version 1.7 by Computourist@gmail.com december 2014 49 | // 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | // 56 | // CONFIGURATION PARAMETERS 57 | // 58 | #define NODEID 3 // unique node ID within the closed network 59 | #define GATEWAYID 1 // node ID of the Gateway is always 1 60 | #define NETWORKID 100 // network ID of the network 61 | #define ENCRYPTKEY "xxxxxxxxxxxxxxxx" // 16-char encryption key; same as on Gateway! 62 | //#define DEBUG // uncomment for debugging 63 | #define VERSION "DHT V1.7" // this value can be queried as device 3 64 | 65 | // Wireless settings Match frequency to the hardware version of the radio 66 | 67 | //#define FREQUENCY RF69_433MHZ 68 | #define FREQUENCY RF69_868MHZ 69 | //#define FREQUENCY RF69_915MHZ 70 | 71 | #define IS_RFM69HW // uncomment only for RFM69HW! 72 | #define ACK_TIME 50 // max # of ms to wait for an ack 73 | 74 | // DHT 11 / sensor setting 75 | #define DHTPIN 4 // DHT data connection 76 | #define DHTTYPE DHT11 // type of sensor 77 | #define ACT1 9 // Actuator pin (LED or relay) 78 | #define BTN 8 // Button pin 79 | #define SERIAL_BAUD 115200 80 | #define HOLDOFF 10000 // blocking period between button messages 81 | 82 | // 83 | // STARTUP DEFAULTS 84 | // 85 | long TXinterval = 60; // periodic transmission interval in seconds 86 | long TIMinterval = 20; // timer interval in seconds 87 | bool ackButton = false; // flag for message on button press 88 | bool toggleOnButton = true; // toggle output on button press 89 | 90 | // 91 | // VARIABLES 92 | // 93 | long lastPeriod = -1; // timestamp last transmission 94 | long lastBtnPress = -1; // timestamp last buttonpress 95 | float hum, temp; // humidity, temperature 96 | int ACT1State; // status ACT1 output 97 | int signalStrength; // radio signal strength 98 | bool setAck = false; // send ACK message on 'SET' request 99 | bool send1, send2, send3, send4; 100 | bool send5, send6, send7, send8; 101 | bool send10, send20, send31, send32; // message triggers 102 | bool promiscuousMode = false; // only listen to nodes within the closed network 103 | bool curState = true; // current button state 104 | bool lastState = true; // last button state 105 | bool wakeUp = true; // wakeup flag 106 | bool timerOnButton = false; // timer output on button press 107 | bool msgBlock = false; // flag to hold button messages to prevent overload 108 | 109 | 110 | typedef struct { // Radio packet format 111 | int nodeID; // node identifier 112 | int devID; // device identifier 113 | int cmd; // read or write 114 | int intVal; // integer payload 115 | float fltVal; // floating payload 116 | char payLoad[10]; // string payload 117 | } Message; 118 | 119 | Message mes; 120 | 121 | DHT dht(DHTPIN, DHTTYPE, 3); // initialise temp/humidity sensor for 3.3 Volt arduino 122 | RFM69 radio; 123 | 124 | // 125 | //===================== SETUP ======================================== 126 | // 127 | void setup() { 128 | #ifdef DEBUG 129 | Serial.begin(SERIAL_BAUD); 130 | #endif 131 | pinMode(ACT1, OUTPUT); // set actuator 1 132 | ACT1State = 0; 133 | digitalWrite(ACT1, ACT1State); 134 | dht.begin(); // initialise temp/hum sensor 135 | radio.initialize(FREQUENCY,NODEID,NETWORKID); // initialise radio 136 | #ifdef IS_RFM69HW 137 | radio.setHighPower(); // only for RFM69HW! 138 | #endif 139 | radio.encrypt(ENCRYPTKEY); // set radio encryption 140 | radio.promiscuous(promiscuousMode); // only listen to closed network 141 | wakeUp = true; // send wakeup message 142 | send8 = false; // initialise button press flag 143 | 144 | #ifdef DEBUG 145 | Serial.print("Node Software Version "); 146 | Serial.println(VERSION); 147 | Serial.print("\nTransmitting at "); 148 | Serial.print(FREQUENCY==RF69_433MHZ ? 433 : FREQUENCY==RF69_868MHZ ? 868 : 915); 149 | Serial.println(" Mhz..."); 150 | #endif 151 | } // end setup 152 | 153 | // 154 | // 155 | //==================== MAIN ======================================== 156 | // 157 | void loop() { 158 | // RECEIVE radio input 159 | // 160 | if (receiveData()) parseCmd(); // receive and parse any radio input 161 | 162 | // DETECT BUTTON PRESS 163 | // 164 | curState = digitalRead(BTN); 165 | msgBlock = (millis() - lastBtnPress < HOLDOFF); // hold-off time for additional button messages 166 | if (curState == LOW && lastState == HIGH) { // button pressed ? 167 | delay(5); 168 | lastBtnPress = millis(); // take timestamp 169 | if (ackButton && !msgBlock) send20 = true; // set button message flag 170 | if (toggleOnButton) { // button in toggle state ? 171 | ACT1State = !ACT1State; // toggle output 172 | digitalWrite(ACT1, ACT1State); 173 | } else 174 | if (TIMinterval > 0 && !timerOnButton) { // button in timer state ? 175 | timerOnButton = true; // start timer interval 176 | ACT1State = HIGH; // switch on ACT1 177 | digitalWrite(ACT1, ACT1State); 178 | } 179 | } 180 | lastState = digitalRead(BTN); 181 | 182 | // TIMER CHECK 183 | // 184 | 185 | if (TIMinterval > 0 && timerOnButton) // =0 means no timer 186 | { 187 | if ( millis() - lastBtnPress > TIMinterval*1000) { // timer expired ? 188 | timerOnButton = false; // then end timer interval 189 | ACT1State = LOW; // and switch off Actuator 190 | digitalWrite(ACT1, ACT1State); 191 | } 192 | } 193 | 194 | // PERIODIC TRANSMISSION 195 | // 196 | 197 | if (TXinterval > 0) 198 | { 199 | int currPeriod = millis()/(TXinterval*1000); 200 | if (currPeriod != lastPeriod) { // interval elapsed ? 201 | lastPeriod = currPeriod; 202 | 203 | // list of sensordata to be sent periodically.. 204 | // remove comment to include parameter in transmission 205 | 206 | // send1 = true; // send transmission interval 207 | // send2 = true; // signal strength 208 | // send4 = true; // voltage level 209 | // send10 = true; // actuator state 210 | send31 = true; // send temperature 211 | send32 = true; // send humidity 212 | } 213 | } 214 | 215 | // SEND RADIO PACKETS 216 | // 217 | 218 | sendMsg(); // send any radio messages 219 | 220 | } // end loop 221 | 222 | // 223 | // 224 | //===================== FUNCTIONS ========================================== 225 | 226 | // 227 | //======== RECEIVEDATA : receive data from gateway over radio 228 | // 229 | 230 | bool receiveData() { 231 | bool validPacket = false; 232 | if (radio.receiveDone()) // check for received packets 233 | { 234 | if (radio.DATALEN != sizeof(mes)) // wrong message size means trouble 235 | #ifdef DEBUG 236 | Serial.println("invalid message structure..") 237 | #endif 238 | ; 239 | else 240 | { 241 | mes = *(Message*)radio.DATA; 242 | validPacket = true; // YES, we have a packet ! 243 | signalStrength = radio.RSSI; 244 | #ifdef DEBUG 245 | Serial.print(mes.devID); 246 | Serial.print(", "); 247 | Serial.print(mes.cmd); 248 | Serial.print(", "); 249 | Serial.print(mes.intVal); 250 | Serial.print(", "); 251 | Serial.print(mes.fltVal); 252 | Serial.print(", RSSI= "); 253 | Serial.println(radio.RSSI); 254 | Serial.print("Node: "); 255 | Serial.println(mes.nodeID); 256 | #endif 257 | } 258 | } 259 | if (radio.ACKRequested()) radio.sendACK(); // respond to any ACK request 260 | return validPacket; // return code indicates packet received 261 | } // end recieveData 262 | 263 | // 264 | // 265 | //============== PARSECMD: analyse messages and execute commands received from gateway 266 | // 267 | 268 | void parseCmd() { // parse messages received from the gateway 269 | send1 = false; // initialise all send triggers 270 | send2 = false; 271 | send3 = false; 272 | send4 = false; 273 | send5 = false; 274 | send6 = false; 275 | send7 = false; 276 | send8 = false; 277 | send10 = false; 278 | send31 = false; 279 | send32 = false; 280 | 281 | switch (mes.devID) // devID indicates device (sensor) type 282 | { 283 | case (1): // polling interval in seconds 284 | if (mes.cmd == 0) { // cmd == 0 means write a value 285 | TXinterval = mes.intVal; // change interval to radio packet value 286 | if (TXinterval <10 && TXinterval !=0) TXinterval = 10; // minimum interval is 10 seconds 287 | if (setAck) send1 = true; // send message if required 288 | #ifdef DEBUG 289 | Serial.print("Setting interval to "); 290 | Serial.print(TXinterval); 291 | Serial.println(" seconds"); 292 | #endif 293 | } 294 | else send1 = true; // cmd == 1 is a read request, so send polling interval 295 | break; 296 | case (2): // signal strength 297 | if (mes.cmd == 1) send2 = true; 298 | break; 299 | case (3): // software version 300 | if (mes.cmd == 1) send3 = true; 301 | break; 302 | case (4): // battery level 303 | if (mes.cmd == 1) send4 = true; 304 | break; 305 | case (5): // set ack status 306 | if (mes.cmd == 0) { 307 | if (mes.intVal == 0) setAck = false; 308 | if (mes.intVal == 1) setAck = true; 309 | if (setAck) send5 = true; // acknowledge message ? 310 | } 311 | else send5 = true; // read request means schedule a message 312 | break; 313 | case (6): // set toggle 314 | if (mes.cmd == 0) { 315 | if (mes.intVal == 0) toggleOnButton = false; 316 | if (mes.intVal == 1) toggleOnButton = true; 317 | if (setAck) send6 = true; // acknowledge message ? 318 | } 319 | else send6 = true; 320 | break; 321 | case (7): // timer interval in seconds 322 | if (mes.cmd == 0) { // cmd == 0 means write a value 323 | TIMinterval = mes.intVal; // change interval 324 | if (TIMinterval <5 && TIMinterval !=0) TIMinterval = 5; 325 | if (setAck) send7 = true; // acknowledge message ? 326 | } // cmd == 1 means read a value 327 | else send7 = true; // send timing interval 328 | break; 329 | case (8): // set button ack status 330 | if (mes.cmd == 0) { 331 | if (mes.intVal == 0) ackButton = false; 332 | if (mes.intVal == 1) ackButton = true; 333 | if (setAck) send8 = true; // acknowledge message ? 334 | } 335 | else send8 = true; 336 | break; 337 | case (10): // Actuator 1 338 | if (mes.cmd == 0) { // cmd == 0 means write 339 | if(mes.intVal == 0 || mes.intVal == 1) { 340 | ACT1State = mes.intVal; 341 | digitalWrite(ACT1, ACT1State); 342 | if (setAck) send10 = true; // acknowledge message ? 343 | #ifdef DEBUG 344 | Serial.print("Set LED to "); 345 | Serial.println(ACT1State); 346 | #endif 347 | }} 348 | else send10 = true; // cmd == 1 means read 349 | break; 350 | case (31): // temperature 351 | if (mes.cmd == 1) send31 = true; 352 | break; 353 | case (32): // humidity 354 | if (mes.cmd == 1) send32 = true; 355 | break; 356 | } 357 | } // end parseCmd 358 | 359 | // 360 | // 361 | //====================== SENDMSG: sends messages that are flagged for transmission 362 | // 363 | 364 | void sendMsg() { // prepares values to be transmitted 365 | bool tx = false; // transmission flag 366 | mes.nodeID=NODEID; 367 | mes.intVal = 0; 368 | mes.fltVal = 0; 369 | mes.cmd = 0; // '0' means no action needed in gateway 370 | int i; 371 | for ( i = 0; i < sizeof(VERSION); i++){ 372 | mes.payLoad[i] = VERSION[i]; } 373 | mes.payLoad[i] = '\0'; // software version in payload string 374 | 375 | if (wakeUp) { // send wakeUp call 376 | mes.devID = 99; 377 | wakeUp = false; // reset transmission flag for this message 378 | txRadio(); // transmit 379 | } 380 | if (send1) { // transmission interval 381 | mes.devID = 1; 382 | mes.intVal = TXinterval; // seconds (integer) 383 | send1 = false; 384 | txRadio(); 385 | } 386 | if (send2) { 387 | mes.devID = 2; 388 | mes.intVal = signalStrength; // signal strength (integer) 389 | send2 = false; 390 | txRadio(); 391 | } 392 | if (send3) { // node software version (string) 393 | mes.devID = 3; // already stored in payload string 394 | send3 = false; 395 | txRadio(); 396 | } 397 | if (send4) { // measure voltage.. 398 | mes.devID = 4; 399 | long result; // Read 1.1V reference against AVcc 400 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 401 | delay(2); // Wait for Vref to settle 402 | ADCSRA |= _BV(ADSC); // Convert 403 | while (bit_is_set(ADCSRA,ADSC)); 404 | result = ADCL; 405 | result |= ADCH<<8; 406 | result = 1126400L / result; // Back-calculate in mV 407 | mes.fltVal = float(result/1000.0); // Voltage in Volt (float) 408 | txRadio(); 409 | send4 = false; 410 | } 411 | if (send5) { // Acknowledge on 'SET' 412 | mes.devID = 5; 413 | if (setAck) mes.intVal = 1; else mes.intVal = 0; // state (integer) 414 | send5 = false; 415 | txRadio(); 416 | } 417 | if (send6) { // Toggle on Buttonpress 418 | mes.devID = 6; 419 | if (toggleOnButton) mes.intVal = 1; // read state of toggle flag 420 | else mes.intVal = 0; // state (integer) 421 | send6 = false; 422 | txRadio(); 423 | } 424 | if (send7) { // timer interval 425 | mes.devID = 7; 426 | mes.intVal = TIMinterval; // seconds (integer) 427 | send7 = false; 428 | txRadio(); 429 | } 430 | if (send8) { // Send Button pressed message 431 | mes.devID = 8; 432 | if (ackButton) mes.intVal = 1; 433 | else mes.intVal = 0; // state (integer) 434 | send8 = false; 435 | txRadio(); 436 | } 437 | if (send10) { // state of Actuator 1 438 | mes.devID = 10; 439 | mes.intVal = ACT1State; // state (integer) 440 | send10 = false; 441 | txRadio(); 442 | } 443 | if (send20) { // Button presssed 444 | mes.devID = 20; 445 | mes.intVal = 1; // state (integer) 446 | send20 = false; 447 | txRadio(); 448 | } 449 | if (send31) { // Temperature 450 | mes.devID = 31; 451 | temp = dht.readTemperature(); 452 | mes.fltVal = temp; // Degrees Celcius (float) 453 | send31 = false; 454 | txRadio(); 455 | } 456 | if (send32) { // Humidity 457 | mes.devID = 32; 458 | hum = dht.readHumidity(); 459 | mes.fltVal = hum; // Percentage (float) 460 | send32 = false; 461 | txRadio(); 462 | } 463 | 464 | 465 | } 466 | // 467 | // 468 | //======================= TXRADIO 469 | // 470 | 471 | void txRadio() // Transmits the 'mes'-struct to the gateway 472 | { 473 | if (radio.sendWithRetry(GATEWAYID, (const void*)(&mes), sizeof(mes))) 474 | #ifdef DEBUG 475 | {Serial.print(" message "); 476 | Serial.print(mes.devID); 477 | Serial.println(" sent...");} 478 | else Serial.println("No connection...") 479 | #endif 480 | ;} // end txRadio 481 | 482 | 483 | 484 | 485 | 486 | -------------------------------------------------------------------------------- /Version_1 Obsolete/Node/RFM_Node_schematic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Version_1 Obsolete/Node/RFM_Node_schematic.jpg -------------------------------------------------------------------------------- /Version_1 Obsolete/RFM_MQTT_gateway_description.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Version_1 Obsolete/RFM_MQTT_gateway_description.pdf -------------------------------------------------------------------------------- /Version_2 Obsolete/RFM_MQTT_gateway_description_V2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/computourist/RFM69-MQTT-client/437aa504a695c5ce42b8ffe8132c331c93c6bb0d/Version_2 Obsolete/RFM_MQTT_gateway_description_V2.pdf --------------------------------------------------------------------------------