Batterie + Solar + 3D Gehäuse + Arduino Pro Mini + RFM95W + DHT22
Finally a real application
Hello friends,
I apologize for the rare posts, I’ve been employed in a makerspace for a few weeks now and I’m not coming to write something. Great fun, but documenting here in the blog…
So, as mentioned in the headline: The first node is running 🙂 Sending every 10 Minutes.
Livedata
Temperature:
Humidity:
Battery:
Construction
The board from the post “My first own TTN node with self designed PCB” certainly known to you, otherwise read the article;)
The structure is thus very simple. The board has everything we need, the DHT22 temperature sensor is simply soldered to the Arduino and ready.
The solar cell is very small, the battery also only in AA (14500) format. No problem with sunshine. We will see how the combination works in winter! I’m curious! However, the battery should last long enough so that winter should not be a problem.
Data processing
The Things Network -> Payload -> NodeRed -> Thingspeak / own Database / …
Technical specifications
- Arduino Pro Mini 3.3V (LowPower mods)
- RFM95W
- 0.15W 5V solar cell
- 900mAh 3.7V LiPo
- Running time about 2 years without sun?
- 5 days sun to fully charge
Runtime Bill
As we learned in the LowPower article here we can expect self-discharge, now and then, deep sleep to consume about 0.04mA.
At 900mAh battery and 0.04mA consumption we come to 900 days. Therefore, winter should not be a problem! Top!
Here’s how the real consumption showed up after 5 months.
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
// Default LoRa libs #include <lmic.h> #include <hal/hal.h> #include <SPI.h> // For this Sketch #include <Wire.h> #include "DHT.h" #include <LowPower.h> // DHT Sensor #define DHTPIN 8 #define DHTTYPE DHT22 DHT dht(DHTPIN, DHTTYPE); // Enable debug prints to serial monitor #define MY_DEBUG // For Mario PCB int BATTERY_SENSE_PIN = A0; int BATTERY_FULL = 4.2; // This EUI must be in little-endian format, so least-significant-byte // first. When copying an EUI from ttnctl output, this means to reverse // the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3, // 0x70. static const u1_t PROGMEM APPEUI[8] = { ToDo }; void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8); } // This should also be in little endian format, see above. static const u1_t PROGMEM DEVEUI[8] = { ToDo }; void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8); } // This key should be in big endian format (or, since it is not really a // number but a block of memory, endianness does not really apply). In // practice, a key taken from ttnctl can be copied as-is. // The key shown here is the semtech default key. static const u1_t PROGMEM APPKEY[16] = { ToDo }; void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16); } static uint8_t mydata[] = "Hello, world!"; // Default static osjob_t sendjob; // 10min -> 12:10 -> 130s zuviel -> pro minute 13s zuviel #define SECPROMIN 13 // Schedule TX every this many seconds (might become longer due to duty // cycle limitations). const unsigned TX_INTERVAL_MINUTES = 10; const unsigned TX_INTERVAL = (60 - SECPROMIN) * TX_INTERVAL_MINUTES; // Pin mapping for Mario PCB const lmic_pinmap lmic_pins = { .nss = 10, .rxtx = LMIC_UNUSED_PIN, .rst = 9, .dio = {4, 5, 7}, }; void onEvent (ev_t ev) { Serial.print(os_getTime()); Serial.print(": "); switch (ev) { case EV_SCAN_TIMEOUT: Serial.println(F("EV_SCAN_TIMEOUT")); break; case EV_BEACON_FOUND: Serial.println(F("EV_BEACON_FOUND")); break; case EV_BEACON_MISSED: Serial.println(F("EV_BEACON_MISSED")); break; case EV_BEACON_TRACKED: Serial.println(F("EV_BEACON_TRACKED")); break; case EV_JOINING: Serial.println(F("EV_JOINING")); break; case EV_JOINED: Serial.println(F("EV_JOINED")); // Disable link check validation (automatically enabled // during join, but not supported by TTN at this time). LMIC_setLinkCheckMode(0); break; case EV_RFU1: Serial.println(F("EV_RFU1")); break; case EV_JOIN_FAILED: Serial.println(F("EV_JOIN_FAILED")); break; case EV_REJOIN_FAILED: Serial.println(F("EV_REJOIN_FAILED")); break; break; case EV_TXCOMPLETE: Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)")); if (LMIC.txrxFlags & TXRX_ACK) Serial.println(F("Received ack")); if (LMIC.dataLen) { Serial.println(F("Received ")); Serial.println(LMIC.dataLen); Serial.println(F(" bytes of payload")); } // Schedule next transmission for (int i = 0; i < int(TX_INTERVAL / 8); i++) { // Use library from https://github.com/rocketscream/Low-Power LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF); } do_send(&sendjob); break; case EV_LOST_TSYNC: Serial.println(F("EV_LOST_TSYNC")); break; case EV_RESET: Serial.println(F("EV_RESET")); break; case EV_RXCOMPLETE: // data received in ping slot Serial.println(F("EV_RXCOMPLETE")); break; case EV_LINK_DEAD: Serial.println(F("EV_LINK_DEAD")); break; case EV_LINK_ALIVE: Serial.println(F("EV_LINK_ALIVE")); break; default: Serial.println(F("Unknown event")); break; } } void do_send(osjob_t* j) { // Read sensor values and multiply by 100 to effectively keep 2 decimals // Signed 16 bits integer, -32767 up to +32767 int16_t t = dht.readTemperature() * 100; // Unsigned 16 bits integer, 0 up to 65535 uint16_t h = dht.readHumidity() * 100; // Unsigned 16 bits integer, 0 up to 65535 uint16_t b = readBat() * 100; byte buffer[6]; buffer[0] = t >> 8; buffer[1] = t; buffer[2] = h >> 8; buffer[3] = h; buffer[4] = b >> 8; buffer[5] = b; LMIC_setTxData2(1, buffer, sizeof(buffer), 0); #ifdef MY_DEBUG Serial.println(""); Serial.print("temperature: "); Serial.print(t); Serial.print(", humidity: "); Serial.print(h); Serial.print(", battery: "); Serial.print(b); Serial.println(""); #endif // Check if there is not a current TX/RX job running if (LMIC.opmode & OP_TXRXPEND) { Serial.println(F("OP_TXRXPEND, not sending")); } else { // Prepare upstream data transmission at the next possible time. LMIC_setTxData2(1, buffer, sizeof(buffer), 0); // LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0); Serial.println(F("Packet queued")); } // Next TX is scheduled after TX_COMPLETE event. } void setup() { Serial.begin(115200); Serial.println(F("Starting")); // Fuer A0 Battery: analogReference(INTERNAL); dht.begin(); delay(2000); #ifdef VCC_ENABLE // For Pinoccio Scout boards pinMode(VCC_ENABLE, OUTPUT); digitalWrite(VCC_ENABLE, HIGH); delay(1000); #endif // LMIC init os_init(); // Reset the MAC state. Session and pending data transfers will be discarded. LMIC_reset(); // Start job (sending automatically starts OTAA too) do_send(&sendjob); } float readBat() { int sensorValue = analogRead(BATTERY_SENSE_PIN); #ifdef MY_DEBUG Serial.println(sensorValue); #endif // 1M, 470K divider across battery and using internal ADC ref of 1.1V // Sense point is bypassed with 0.1 uF cap to reduce noise at that point // ((1e6+470e3)/470e3)*1.1 = Vmax = 3.44 Volts // 3.44/1023 = Volts per bit = 0.003363075 // 2M, 470K 1.1V ref => 5,78V Max! // 5,78/1023 = 0.00565 float batteryV = sensorValue * 0.00565; #ifdef MY_DEBUG Serial.print("Battery Voltage: "); Serial.print(batteryV); Serial.println(" V"); #endif return batteryV; } void loop() { os_runloop_once(); } |
Affiliate links:
If you order through any of the following AliExpress links, I get about 8% commission 😉
Soshine 4pc 3.7V ICR 14500 900mAh Li-ion
Mini 0.15W 5V Solar Panel
DHT22 single-bus digital temperature and humidity sensor
Mario, el código que propones para Arduino no compila. Tienes que tener en cuenta los pines del SPI
Hola, funcionó para mí en ese momento. Puede ser que algo haya cambiado en la biblioteca.
Hey Mario,
mega interessantes Projekt und genau das, was ich gerade suche! Allerdings habe ich das Problem, wenn ich deinen Code per Copy and Paste ausprobiere, dass mir der Fehler für den Arduino Pro Mini angezeigt wird: “Der Sketch verwendet 25280 Bytes (82%) des Programmspeicherplatzes. Das Maximum sind 30720 Bytes.
Globale Variablen verwenden 2329 Bytes (113%) des dynamischen Speichers, -281 Bytes für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.”
Ich hab mit dem RFM95 noch überhaupt keine Erfahrung gesammelt und keine Ahnung, wie ich libraries ausdünnen kann. Wie hat das bei dir geklappt? Wäre dir wirklich sehr für eine Idee dankbar, was ich falsch mache 😀
LG
Johannes
Hallo Mario,
hat sich erledigt, ich habe den Fehler gefunden! Die Libraries haben sich nicht korrekt installiert oder so..
Freut mich das es klappt 🙂
Very nice post, regarding the payload format in TTN, how it’s work?
function Decoder(bytes, port) {
var t = (bytes[0] & 0x80 ? 0xFFFF<<16 : 0) | bytes[0]<<8 | bytes[1]; var h = bytes[2]<<8 | bytes[3]; var b = bytes[4]<<8 | bytes[5]; var p = (bytes[6]<<8 | bytes[7]) * 100 + (bytes[8]<<8 | bytes[9]) / 100; return { temperature: t / 100, humidity: h / 100, battery: b / 100, pressure: p } }
Tolle Idee!
Habe mir zwei Boards nachgebaut, aber anscheinend sendet keines von beiden…
Weshalb hast du DIO9 des Arduino nochmal verkabelt?
Gruß – Sven
Komisch. D9 ist der Reset Pin zum Arduino. Ich habe inzwischen das 10 Board oder so verbaut. I.d.R. klappt alles. Kommst du aus der Nähe Oberhausen?
Hello,
this seems to be a very nice project. Currently I to try to rebuild this since some days, always when I have a bit of time and I use a breadboard for the first experiments. Connections are fine and a “hello world” example is also working. However, extending the code and implementing a sensor like you show yields already some problems.
May I ask which versions of the libraries did you install? The current ones seem to be too big such that stability problems occur and the program does not do what is should (I use the serial monitor for debugging).
– MCCI LoRaWAN LMIC Library – version ???
– DHT sensor library – version ???
– Arduino Low Power – version ???
– Wire – version ???
Best regards!
Felix
LMIC 1.5
DHT 1.3.0
LowPower 1.6
Hi,
thanks a lot. I could succeed with IBM LMIC framework (matthijskooijman/IBM LMIC framework 1.5.1). Is this the one you used? It takes between 5-10 min until the µC can join the network. Once it joined, it runs stable. Is this normal?
I rebuild the project with an ESP32 – just out of curiosity, and the ESP32 setup joins the network almost immediately. I did multiple tries for a conclusive result.
I will try with STM32 in the near future.
Best regards!
Felix
Hello Mario
I’m designing a lora transmitter also, I’ve very surprised yours have a few similar aspects to mine ! Very happy to find yours !! Do you share your 3D files, weatherproof box ?
the one here :
https://www.thethingsnetwork.org/forum/uploads/default/original/2X/9/97f45ca4a8fed27f7280cbaf54234ebe6425547a.jpg
Hello,
I hope it is not too late.
PCB:
https://oshwlab.com/mariozw/TTN-dd5f957581974c02a573633d15e9e668
https://easyeda.com/mariozw/TTN-dd5f957581974c02a573633d15e9e668
I still don’t have all the stuff on Thingiverse unfortunately, but I’m happy to share my Fusion360 project. I think you can export whole bodies as STL.
Not all of the designs I have printed out. Many were just concepts. But they can still fit. I just do not know it anymore 😀
https://a360.co/35BukKb
https://a360.co/3bkoQHk
https://a360.co/3or7ThQ
Greetings
Super Projekt 😉 Lora ist wirklich ein gutes Thema.
Ich hab mal versucht dein Projekt nachzubauen, ich bekomme im SerialMonitor aber einen Fehler:
Packet queued
128271: EV_JOINING
238230: Unknown event
Im Gateway unter Traffic kommt alles an aber unter der Application des Sensor keine Daten? Hast du einen Tipp für mich ?
grüße Tobi
Hei Tobi,
ja, du hast die falschen Keys eingetragen. Wenn das Paket nur auf dem Gateway zu erkennen ist, ist irgendetwas falsch.
Falsche AppKey -> kein entschlüsseln. Falsche DevAdrr -> keine Zuordnung, ..
Achte darauf, dass die meisten Bibliotheken die Keys in Hex Form haben möchten. Manche in LSB manche in MSB (welches Bit kommt zuerst..)
Manchmal steht es dabei, manchmal muss man ausprobieren.
Grüße!