├── .gitignore ├── .travis.yml ├── 3D ├── LoRa Base Case.f3d ├── LoRa Base Case.stl ├── Lora Base Case Deckel.f3d └── Lora Base Case Deckel.stl ├── README.md ├── gerber ├── promini_rfm95.jpg └── promini_rfm95.zip ├── img ├── case_3d.jpg ├── case_open.jpg ├── circuit.jpg ├── value_plot.jpg └── vcc_plot.jpg ├── include ├── io_pins.h ├── lora_credentials.h.example ├── settings.h ├── version.h └── version_build.h ├── platformio.ini ├── src ├── functions.cpp ├── functions.h ├── global.cpp ├── global.h ├── lorawan.cpp ├── lorawan.h ├── main.cpp ├── powerdown.cpp └── powerdown.h └── tools └── platformio_versioning.py /.gitignore: -------------------------------------------------------------------------------- 1 | ### PlatformIO ### 2 | .pioenvs 3 | .piolibdeps 4 | .clang_complete 5 | .gcc-flags.json 6 | .pio 7 | 8 | ### VisualStudioCode ### 9 | .vscode/* 10 | #!.vscode/settings.json 11 | !.vscode/tasks.json 12 | #!.vscode/launch.json 13 | #!.vscode/extensions.json 14 | *.bak 15 | 16 | ### VisualStudioCode Patch ### 17 | # Ignore all local history of files 18 | .history 19 | 20 | # credentials 21 | *_credentials.h 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < https://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < https://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choose one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # - platformio update 39 | # 40 | # script: 41 | # - platformio run 42 | 43 | 44 | # 45 | # Template #2: The project is intended to be used as a library with examples. 46 | # 47 | 48 | # language: python 49 | # python: 50 | # - "2.7" 51 | # 52 | # sudo: false 53 | # cache: 54 | # directories: 55 | # - "~/.platformio" 56 | # 57 | # env: 58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 59 | # - PLATFORMIO_CI_SRC=examples/file.ino 60 | # - PLATFORMIO_CI_SRC=path/to/test/directory 61 | # 62 | # install: 63 | # - pip install -U platformio 64 | # - platformio update 65 | # 66 | # script: 67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 68 | -------------------------------------------------------------------------------- /3D/LoRa Base Case.f3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/3D/LoRa Base Case.f3d -------------------------------------------------------------------------------- /3D/LoRa Base Case.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/3D/LoRa Base Case.stl -------------------------------------------------------------------------------- /3D/Lora Base Case Deckel.f3d: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/3D/Lora Base Case Deckel.f3d -------------------------------------------------------------------------------- /3D/Lora Base Case Deckel.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/3D/Lora Base Case Deckel.stl -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino Pro Mini TTN LoRaWAN sensor node 2 | 3 | 4 | 5 | `Arduino Pro Mini` TTN LoRaWAN Node with `DHT22` and `RFM95` module powered by an 18650 protected battery. 6 | The Arduino was converted to [LowPower](https://jackgruber.github.io/2019-12-27-Low-power-Arduino-Pro-Mini/) by desoldering the power LED and the voltage converter. 7 | 8 | ## Circuit 9 | 10 | 11 | 12 | 13 | ## Case 14 | 15 | 16 | 17 | ## Diagrams 18 | 19 | 20 | ### Battery voltage curve over 12 months with measure and send data all 5 minutes 21 | 22 | 23 | 24 | ## TTN payload decoder (v2) 25 | 26 | ```javascript 27 | function Decoder(bytes, port) { 28 | var decoded = {}; 29 | 30 | decoded.vcc = (bytes[0] + 200)/100; 31 | 32 | if(bytes[1] != 255){ 33 | decoded.humidity = bytes[1]; 34 | decoded.humidity &= ~(1 << 7); 35 | if(bytes[1] >> 7 == 1) { decoded.humidity +=0.5 } 36 | } 37 | 38 | if(bytes[2] != 255 || bytes[3] != 255) decoded.temperature = ((bytes[2]<<24>>16 | bytes[3]) / 10); 39 | return decoded; 40 | } 41 | ``` 42 | 43 | ## TTN payload decoder (v3) 44 | 45 | ```javascript 46 | function decodeUplink(input) { 47 | var decoded = {}; 48 | decoded.vcc = (input.bytes[0] + 200)/100; 49 | if(input.bytes[1] != 255){ 50 | decoded.humidity = input.bytes[1]; 51 | decoded.humidity &= ~(1 << 7); 52 | if(input.bytes[1] >> 7 == 1) { decoded.humidity +=0.5 } 53 | } 54 | if(input.bytes[2] != 255 || input.bytes[3] != 255) decoded.temperature = ((input.bytes[2]<<24>>16 | input.bytes[3]) / 10); 55 | 56 | return { 57 | data: decoded, 58 | warnings: [], 59 | errors: [] 60 | }; 61 | } 62 | ``` 63 | -------------------------------------------------------------------------------- /gerber/promini_rfm95.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/gerber/promini_rfm95.jpg -------------------------------------------------------------------------------- /gerber/promini_rfm95.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/gerber/promini_rfm95.zip -------------------------------------------------------------------------------- /img/case_3d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/img/case_3d.jpg -------------------------------------------------------------------------------- /img/case_open.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/img/case_open.jpg -------------------------------------------------------------------------------- /img/circuit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/img/circuit.jpg -------------------------------------------------------------------------------- /img/value_plot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/img/value_plot.jpg -------------------------------------------------------------------------------- /img/vcc_plot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JackGruber/Arduino-Pro-Mini-LoRa-Sensor-Node/d9527fde1e6a68f36523b1b5a9d133e53c6bb45e/img/vcc_plot.jpg -------------------------------------------------------------------------------- /include/io_pins.h: -------------------------------------------------------------------------------- 1 | #define PIN_DHT 3 2 | #define PIN_INFO_LED 9 3 | 4 | // PIN definition for module 5 | #define PIN_LMIC_NSS 10 6 | #define PIN_LMIC_RST A0 7 | #define PIN_LMIC_DIO0 5 8 | #define PIN_LMIC_DIO1 6 9 | #define PIN_LMIC_DIO2 7 -------------------------------------------------------------------------------- /include/lora_credentials.h.example: -------------------------------------------------------------------------------- 1 | #define TTN_APPEUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // TTN Application EUI with "lsb" 2 | #define TTN_DEVEUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // TTN Device EUI with "lsb" 3 | #define TTN_APPKEY { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // TTN App Key with "msb" 4 | -------------------------------------------------------------------------------- /include/settings.h: -------------------------------------------------------------------------------- 1 | #define LORA_TX_INTERVAL 300 2 | #define LMIC_LORA_SF DR_SF7 // LORA Data rate 3 | -------------------------------------------------------------------------------- /include/version.h: -------------------------------------------------------------------------------- 1 | #define VERSION_MAJOR "1" 2 | #define VERSION_MINOR "0" 3 | #define VERSION_PATCH "0" 4 | #define VERSION_BUILD "0" 5 | -------------------------------------------------------------------------------- /include/version_build.h: -------------------------------------------------------------------------------- 1 | #define BUILD_BRANCH "" 2 | #define BUILD_COMMIT "" 3 | #define BUILD_DATE "" 4 | #define BUILD_TIME "" 5 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ;PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | ; USBASP Upload command 12 | ; io run -t program --upload-port usb 13 | 14 | [env:pro8MHzatmega328] 15 | platform = atmelavr 16 | board = pro8MHzatmega328 17 | framework = arduino 18 | monitor_speed = 115200 19 | upload_protocol = usbasp 20 | extra_scripts = 21 | pre:tools/platformio_versioning.py 22 | 23 | upload_flags = 24 | -Pusb 25 | -e ; Erase chip bevor upload 26 | 27 | lib_deps = 28 | mcci-catena/MCCI LoRaWAN LMIC library @ ^4.0.0 29 | https://github.com/markruys/arduino-DHT 30 | 31 | build_flags = 32 | -D ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS 33 | -D CFG_eu868=1 34 | -D CFG_sx1276_radio=1 35 | -D LMIC_PRINTF_TO=Serial 36 | -D LMIC_DEBUG_LEVEL=0 37 | -D DISABLE_PING=1 38 | -D DISABLE_BEACONS=1 39 | -D LORADEV=KELLER 40 | -------------------------------------------------------------------------------- /src/functions.cpp: -------------------------------------------------------------------------------- 1 | #include "functions.h" 2 | #include "io_pins.h" 3 | #include "global.h" 4 | #include "DHT.h" 5 | 6 | void Setup_Pins() 7 | { 8 | pinMode(PIN_INFO_LED, OUTPUT); 9 | } 10 | 11 | void Blink_Info_LED() 12 | { 13 | digitalWrite(PIN_INFO_LED, HIGH); 14 | delay(30); 15 | digitalWrite(PIN_INFO_LED, LOW); 16 | delay(30); 17 | } 18 | 19 | // https://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ 20 | long ReadVcc() { 21 | // Read 1.1V reference against AVcc 22 | // set the reference to Vcc and the measurement to the internal 1.1V reference 23 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) 24 | ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 25 | #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 26 | ADMUX = _BV(MUX5) | _BV(MUX0); 27 | #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 28 | ADMUX = _BV(MUX3) | _BV(MUX2); 29 | #else 30 | ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); 31 | #endif 32 | 33 | delay(2); // Wait for Vref to settle 34 | ADCSRA |= _BV(ADSC); // Start conversion 35 | while (bitRead(ADCSRA, ADSC)); 36 | 37 | uint8_t adc_low = ADCL; // must read ADCL first - it then locks ADCH 38 | uint8_t adc_high = ADCH; // unlocks both 39 | long adc_result = (adc_high<<8) | adc_low; 40 | adc_result = 1125300L / adc_result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 41 | return adc_result; // Vcc in millivolts 42 | } 43 | 44 | void ReadDHTSensor() 45 | { 46 | float t = DHTSENSOR.getTemperature(); 47 | float h = DHTSENSOR.getHumidity(); 48 | 49 | Serial.print("DHT: "); 50 | Serial.println(DHTSENSOR.getStatusString()); 51 | 52 | HUMIDITY = h; 53 | TEMPERATURE = t; 54 | 55 | Serial.print(HUMIDITY); 56 | Serial.println(" %"); 57 | Serial.print(TEMPERATURE); 58 | Serial.println(" °C"); 59 | } 60 | 61 | void PrintResetReason() 62 | { 63 | uint8_t mcusr_copy = MCUSR; 64 | MCUSR = 0; 65 | Serial.print("MCUSR:"); 66 | if(mcusr_copy & (1< 6 | 7 | void Setup_Pins(void); 8 | void Blink_Info_LED(void); 9 | long ReadVcc(void); 10 | void ReadDHTSensor(void); 11 | void PrintResetReason(void); 12 | #endif -------------------------------------------------------------------------------- /src/global.cpp: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "io_pins.h" 3 | 4 | float HUMIDITY = NAN; 5 | float TEMPERATURE = NAN; 6 | DHT DHTSENSOR; 7 | -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _GLOBAL_H 3 | #define _GLOBAL_H 4 | 5 | #include 6 | #include 7 | 8 | extern volatile int POWER_DOWN_SLEEP_COUNTER; 9 | extern float HUMIDITY; 10 | extern float TEMPERATURE; 11 | extern DHT DHTSENSOR; 12 | #endif -------------------------------------------------------------------------------- /src/lorawan.cpp: -------------------------------------------------------------------------------- 1 | #include "lorawan.h" 2 | #include "settings.h" 3 | #include 4 | #include 5 | #include "io_pins.h" 6 | #include "powerdown.h" 7 | #include "functions.h" 8 | #include "global.h" 9 | 10 | // Pin mapping 11 | const lmic_pinmap lmic_pins = { 12 | .nss = PIN_LMIC_NSS, 13 | .rxtx = LMIC_UNUSED_PIN, 14 | .rst = PIN_LMIC_RST, 15 | .dio = {PIN_LMIC_DIO0, PIN_LMIC_DIO1, PIN_LMIC_DIO2}, 16 | }; 17 | 18 | static uint8_t LORA_DATA[4]; 19 | 20 | // Schedule TX every this many seconds (might become longer due to duty cycle limitations). 21 | const unsigned TX_INTERVAL = LORA_TX_INTERVAL; 22 | 23 | void os_getArtEui(u1_t *buf) { memcpy_P(buf, APPEUI, 8); } 24 | void os_getDevEui(u1_t *buf) { memcpy_P(buf, DEVEUI, 8); } 25 | void os_getDevKey(u1_t *buf) { memcpy_P(buf, APPKEY, 16); } 26 | 27 | bool GO_DEEP_SLEEP = false; 28 | 29 | void LoRaWANSetup() 30 | { 31 | Serial.println(F("LoRaWAN_Setup ...")); 32 | 33 | // LMIC init 34 | os_init(); 35 | 36 | // Reset the MAC state. Session and pending data transfers will be discarded. 37 | LMIC_reset(); 38 | 39 | // Let LMIC compensate for +/- 1% clock error 40 | LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); 41 | 42 | // Start job 43 | LoRaWANDo_send(&sendjob); 44 | } 45 | 46 | void LoRaWANDo_send(osjob_t *j) 47 | { 48 | // Check if there is not a current TX/RX job running 49 | if (LMIC.opmode & OP_TXRXPEND) 50 | { 51 | Serial.println(F("OP_TXRXPEND, not sending")); 52 | } 53 | else 54 | { 55 | LoRaWANGetData(); 56 | 57 | // Prepare upstream data transmission at the next possible time. 58 | LMIC_setTxData2(1, LORA_DATA, sizeof(LORA_DATA), 0); 59 | Serial.println(F("Packet queued")); 60 | } 61 | // Next TX is scheduled after TX_COMPLETE event. 62 | } 63 | 64 | void onEvent(ev_t ev) 65 | { 66 | Serial.print(os_getTime()); 67 | Serial.print(": "); 68 | switch (ev) 69 | { 70 | case EV_SCAN_TIMEOUT: 71 | Serial.println(F("EV_SCAN_TIMEOUT")); 72 | break; 73 | case EV_BEACON_FOUND: 74 | Serial.println(F("EV_BEACON_FOUND")); 75 | break; 76 | case EV_BEACON_MISSED: 77 | Serial.println(F("EV_BEACON_MISSED")); 78 | break; 79 | case EV_BEACON_TRACKED: 80 | Serial.println(F("EV_BEACON_TRACKED")); 81 | break; 82 | case EV_JOINING: 83 | Serial.println(F("EV_JOINING")); 84 | break; 85 | case EV_JOINED: 86 | Serial.println(F("EV_JOINED")); 87 | #ifndef DISABLE_JOIN 88 | { 89 | u4_t netid = 0; 90 | devaddr_t devaddr = 0; 91 | u1_t nwkKey[16]; 92 | u1_t artKey[16]; 93 | LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey); 94 | Serial.print("netid: "); 95 | Serial.println(netid, DEC); 96 | Serial.print("devaddr: "); 97 | Serial.println(devaddr, HEX); 98 | Serial.print("artKey: "); 99 | for (size_t i = 0; i < sizeof(artKey); ++i) 100 | { 101 | Serial.print(artKey[i], HEX); 102 | } 103 | Serial.println(""); 104 | Serial.print("nwkKey: "); 105 | for (size_t i = 0; i < sizeof(nwkKey); ++i) 106 | { 107 | Serial.print(nwkKey[i], HEX); 108 | } 109 | Serial.println(""); 110 | } 111 | // Disable link check validation (automatically enabled 112 | // during join, but because slow data rates change max TX 113 | // size, we don't use it in this example. 114 | LMIC_setLinkCheckMode(0); 115 | #endif 116 | break; 117 | /* 118 | || This event is defined but not used in the code. No 119 | || point in wasting codespace on it. 120 | || 121 | || case EV_SCAN_FOUND: 122 | || Serial.println(F("EV_SCAN_FOUND")); 123 | || break; 124 | */ 125 | case EV_JOIN_FAILED: 126 | Serial.println(F("EV_JOIN_FAILED")); 127 | break; 128 | case EV_REJOIN_FAILED: 129 | Serial.println(F("EV_REJOIN_FAILED")); 130 | break; 131 | case EV_TXCOMPLETE: 132 | Serial.println(F("EV_TXCOMPLETE")); 133 | 134 | if (LMIC.txrxFlags & TXRX_ACK) 135 | { 136 | Serial.println(F("Received ack")); 137 | } 138 | 139 | if (LMIC.dataLen) 140 | { 141 | Serial.print(LMIC.dataLen); 142 | Serial.println(F(" bytes of payload")); 143 | } 144 | 145 | // Schedule next transmission 146 | os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), LoRaWANDo_send); 147 | GO_DEEP_SLEEP = true; 148 | 149 | break; 150 | case EV_LOST_TSYNC: 151 | Serial.println(F("EV_LOST_TSYNC")); 152 | break; 153 | case EV_RESET: 154 | Serial.println(F("EV_RESET")); 155 | break; 156 | case EV_RXCOMPLETE: 157 | // data received in ping slot 158 | Serial.println(F("EV_RXCOMPLETE")); 159 | break; 160 | case EV_LINK_DEAD: 161 | Serial.println(F("EV_LINK_DEAD")); 162 | break; 163 | case EV_LINK_ALIVE: 164 | Serial.println(F("EV_LINK_ALIVE")); 165 | break; 166 | /* This event is defined but not used in the code. 167 | case EV_SCAN_FOUND: 168 | DisplayPrintln(F("EV_SCAN_FOUND"), LORAWAN_STATE_DISPLAY_LINE); 169 | break; 170 | */ 171 | case EV_TXSTART: 172 | Serial.println(F("EV_TXSTART")); 173 | break; 174 | case EV_TXCANCELED: 175 | Serial.println(F("EV_TXCANCELED")); 176 | break; 177 | case EV_RXSTART: 178 | /* do not print anything -- it wrecks timing */ 179 | break; 180 | case EV_JOIN_TXCOMPLETE: 181 | Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept")); 182 | break; 183 | default: 184 | Serial.print(F("Unknown event: ")); 185 | Serial.println((unsigned)ev); 186 | break; 187 | } 188 | } 189 | 190 | void LoRaWANDo(void) 191 | { 192 | if (GO_DEEP_SLEEP == true) 193 | { 194 | PowerDownTXIntervall(); 195 | GO_DEEP_SLEEP = false; 196 | } 197 | else 198 | { 199 | os_runloop_once(); 200 | } 201 | } 202 | 203 | void LoRaWANGetData() 204 | { 205 | ReadDHTSensor(); 206 | 207 | uint8_t vcc = (ReadVcc() / 10) - 200; 208 | 209 | uint8_t humidity_lora = HUMIDITY; 210 | 211 | int16_t temp = (TEMPERATURE * 10); 212 | 213 | if (isnan(TEMPERATURE)) 214 | { 215 | LORA_DATA[2] = 255; 216 | LORA_DATA[3] = 255; 217 | } 218 | else 219 | { 220 | LORA_DATA[2] = temp >> 8; 221 | LORA_DATA[3] = temp & 0xFF; 222 | } 223 | 224 | if (isnan(HUMIDITY)) 225 | { 226 | LORA_DATA[1] = 255; 227 | } 228 | else 229 | { 230 | float check = HUMIDITY - humidity_lora; 231 | LORA_DATA[1] = humidity_lora; 232 | 233 | // Bit 8 for decimal 1 = 0.5 234 | if (check > 0.251 && check < 0.751) 235 | { 236 | LORA_DATA[1] |= (1 << 7); 237 | } 238 | else if (check > 0.751) 239 | { 240 | LORA_DATA[1] = LORA_DATA[1] + 1; 241 | } 242 | } 243 | 244 | LORA_DATA[0] = vcc; 245 | } 246 | 247 | void LoRaWANVersion() 248 | { 249 | Serial.print(F("LMIC: ")); 250 | Serial.print(ARDUINO_LMIC_VERSION_GET_MAJOR(ARDUINO_LMIC_VERSION)); 251 | Serial.print(F(".")); 252 | Serial.print(ARDUINO_LMIC_VERSION_GET_MINOR(ARDUINO_LMIC_VERSION)); 253 | Serial.print(F(".")); 254 | Serial.print(ARDUINO_LMIC_VERSION_GET_PATCH(ARDUINO_LMIC_VERSION)); 255 | Serial.print(F(".")); 256 | Serial.println(ARDUINO_LMIC_VERSION_GET_LOCAL(ARDUINO_LMIC_VERSION)); 257 | } -------------------------------------------------------------------------------- /src/lorawan.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #ifndef _LORAWAN_H 3 | #define _LORAWAN_H 4 | 5 | #include 6 | #include 7 | #include "lora_credentials.h" 8 | 9 | // This EUI must be in little-endian format, so least-significant-byte 10 | // first. When copying an EUI from ttnctl output, this means to reverse 11 | // the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, 12 | // 0x70. 13 | static const u1_t PROGMEM APPEUI[8] = TTN_APPEUI; 14 | 15 | // This should also be in little endian format, see above. 16 | static const u1_t PROGMEM DEVEUI[8] = TTN_DEVEUI; 17 | 18 | // This key should be in big endian format (or, since it is not really a 19 | // number but a block of memory, endianness does not really apply). In 20 | // practice, a key taken from ttnctl can be copied as-is. 21 | static const u1_t PROGMEM APPKEY[16] = TTN_APPKEY; 22 | 23 | static osjob_t sendjob; 24 | 25 | void os_getArtEui(u1_t *buf); 26 | void os_getDevEui(u1_t *buf); 27 | void os_getDevKey(u1_t *buf); 28 | 29 | void LoRaWANSetup(void); 30 | void LoRaWANDo_send(osjob_t *j); 31 | void LoRaWANDo(void); 32 | void LoRaWANGetData(void); 33 | void LoRaWANVersion(void); 34 | 35 | #endif -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "io_pins.h" 3 | #include "functions.h" 4 | #include "lorawan.h" 5 | #include "global.h" 6 | #include "powerdown.h" 7 | #include "version.h" 8 | #include "version_build.h" 9 | 10 | void setup() 11 | { 12 | Serial.begin(115200); 13 | Serial.println(F("Starting DHT ...")); 14 | Serial.println("Sketch: " VERSION_MAJOR "." VERSION_MINOR "." VERSION_PATCH "." BUILD_COMMIT "-" BUILD_BRANCH); 15 | Serial.println("Builddate: " BUILD_DATE " " BUILD_TIME); 16 | PrintResetReason(); 17 | LoRaWANVersion(); 18 | delay(3000); 19 | DHTSENSOR.setup(PIN_DHT); 20 | PowerDownSetupWatchdog(); 21 | Setup_Pins(); 22 | Blink_Info_LED(); 23 | LoRaWANSetup(); 24 | } 25 | 26 | void loop() 27 | { 28 | LoRaWANDo(); 29 | } 30 | -------------------------------------------------------------------------------- /src/powerdown.cpp: -------------------------------------------------------------------------------- 1 | #include "powerdown.h" 2 | #include 3 | #include "settings.h" 4 | 5 | volatile int POWER_DOWN_SLEEP_COUNTER = 0; 6 | 7 | 8 | void PowerDownUpdateMicros() 9 | { 10 | extern volatile unsigned long timer0_overflow_count; 11 | PowerDown(); 12 | cli(); 13 | // LMIC uses micros() to keep track of the duty cycle, so 14 | // hack timer0_overflow for a rude adjustment: 15 | timer0_overflow_count+= 8 * 64 * clockCyclesPerMicrosecond(); 16 | sei(); 17 | } 18 | 19 | void PowerDown() 20 | { 21 | ADCSRA &= ~(1< 6 | 7 | void PowerDownUpdateMicros(void); 8 | void PowerDown(void); 9 | void PowerDownSetupWatchdog(void); 10 | void PowerDownTXIntervall(void); 11 | 12 | #endif -------------------------------------------------------------------------------- /tools/platformio_versioning.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | # Optional: Define Path to your local verison of https://github.com/JackGruber/auto_buildnumber 5 | # If it is not located at a position same folder as `platformio_versioning.py` 6 | autoversion = 'C:\\git\\meine\\auto_buildnumber' 7 | 8 | try: 9 | import versioning 10 | autver_ok = True 11 | except: 12 | if os.path.exists(autoversion): 13 | sys.path.insert(0, autoversion) 14 | try: 15 | import versioning 16 | autver_ok = True 17 | except: 18 | autver_ok = False 19 | else: 20 | autver_ok = False 21 | 22 | if autver_ok == True: 23 | versioning.UpdateVersionFile("include/version.h", "DEFINEHEADER", False, "include/version_build.h") 24 | --------------------------------------------------------------------------------