diff --git a/README.md b/README.md index 2d88778..c802837 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ Before Compiling and Flashing make sure to copy config.h.example to config.h and Programming is done using a [MicroUPDI Programmer](https://github.com/MCUdude/microUPDI) - for other pogramming variants see the MegaTinyCore documentation. +## Configuring via Downlink + +It is possible to change the sending interval via Downlink-Packets at runtime. The time between Transmits is specified in minutes (or more exactly, 64 Second intervals) and has to be sent as a 2 byte value, which will be interpreted as an uint. so for example 0x0001 means 1 Minute, 0x0002 means 2 Minutes and so on. Sending 0xFFFF resets the value to the compiled in default. + ## Acknowledgements Parts of this code where kindly provided by [@shempe](https://twitter.com/shempe) diff --git a/firmware/config.h.example b/firmware/config.h.example index 6074593..0340448 100644 --- a/firmware/config.h.example +++ b/firmware/config.h.example @@ -2,19 +2,27 @@ // ATTNode v3 Onboard LED is on PIN_PA7 #define LED_PIN PIN_PA7 +// Enable Serial Debugging. Parameters for the Serial Port are 115200 +// #define DEBUG + // Define which Sensor is installed #define HAS_BME280 // #define HAS_SHT21 // #define HAS_NO_SENSOR -// How many Minutes to sleep between Measuring/Sending +// How many minutes to sleep between Measuring/Sending +// Since this is a 2-byte value internally, intervals between 1 and 65536 are possible +// This is the default interval to use, which can be overwritten via DownLink. If an interval +// is set via DownLink it will be saved in EEPROM and the time specified here will no longer be used. // Actual Sleep Time is SLEEP_TIME*2*32 Seconds due to the 32s sleep intervals of the ATTiny3216 #define SLEEP_TIME 10 -// Specify TTN EU Bandplan and LoRa Chip for the LMIC +// Specify TTN EU Bandplan and LoRa Chip for the LMIC as well as Disabling some unused functions // See LMIC documentation / project_config.h for more options #define CFG_eu868 1 #define CFG_sx1276_radio 1 +#define DISABLE_PING +#define DISABLE_BEACONS // Keys for OTAA Mode // APPEUI and DEVEUI from TTN, LSB! diff --git a/firmware/debug.h b/firmware/debug.h new file mode 100644 index 0000000..593deb3 --- /dev/null +++ b/firmware/debug.h @@ -0,0 +1,16 @@ +/* +DebugUtils.h - Simple debugging utilities. +*/ + +#ifndef DEBUGUTILS_H +#define DEBUGUTILS_H + +#ifdef DEBUG + #define DEBUG_PRINT(...) Serial.print(__VA_ARGS__); Serial.flush(); + #define DEBUG_PRINTLN(...) Serial.println(__VA_ARGS__); Serial.flush(); +#else + #define DEBUG_PRINT(...) + #define DEBUG_PRINTLN(...) +#endif + +#endif diff --git a/firmware/firmware.ino b/firmware/firmware.ino index 49cf5f4..e98b217 100644 --- a/firmware/firmware.ino +++ b/firmware/firmware.ino @@ -4,12 +4,17 @@ #include #include #include +#include + +// Keep Track of used EEPROM Addresses +#define ADDR_SLP 0 // Sleep Interval, 2 Bytes // Use the local config.h for LMIC Configuration #define ARDUINO_LMIC_PROJECT_CONFIG_H config.h #include #include #include "config.h" +#include "debug.h" #ifdef HAS_BME280 #include "BME280.h" @@ -42,7 +47,11 @@ const lmic_pinmap lmic_pins = { }; // List of unused Pins - will be disabled for Power Saving +#ifdef DEBUG +const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0}; +#else const int disabledPins[] = {PIN_PB5, PIN_PB4, PIN_PB3, PIN_PB2, PIN_PB1, PIN_PB0, PIN_PC3, PIN_PC2, PIN_PC1, PIN_PC0}; +#endif // ISR Routine for Sleep ISR(RTC_PIT_vect) @@ -73,13 +82,28 @@ void onEvent(ev_t ev) { case EV_JOINED: // Disable LinkCheck LMIC_setLinkCheckMode(0); + DEBUG_PRINTLN("OTAA Join Succeeded"); break; case EV_TXCOMPLETE: + // Check for Downlink + DEBUG_PRINTLN("LoRa Packet Sent"); + if ((int)LMIC.dataLen == 2) { + // We got a Packet with the right size - lets assemble it into a uint16_t + DEBUG_PRINTLN("Received Downlink") + uint16_t tmpslp = (LMIC.frame[LMIC.dataBeg] << 8) | LMIC.frame[LMIC.dataBeg+1]; + DEBUG_PRINT("Setting Sleep Time to: "); + DEBUG_PRINTLN(tmpslp); + sleep_time = tmpslp; + EEPROM.put(ADDR_SLP, tmpslp); + } + + // Got to sleep for specified Time + DEBUG_PRINTLN("Going to Sleep"); + for (uint16_t i = 0; i < sleep_time*2; i++) + sleep_32s(); + // Schedule Next Transmit do_send(&sendjob); - // Got to sleep for specified Time - for (int i = 0; i < int(SLEEP_TIME*2); i++) - sleep_32s(); break; } } @@ -152,17 +176,21 @@ void do_send(osjob_t* j) { sensor.getData(&data.temperature, &data.pressure, &data.humidity); #endif - // Queue Paket for Sending + // Queue Packet for Sending + DEBUG_PRINTLN("LoRa-Packet Queued"); LMIC_setTxData2(1, (unsigned char *)&data, sizeof(data), 0); } } void setup() { + #ifdef DEBUG + Serial.begin(115200); + #endif // Initialize SPI and I2C Wire.begin(); SPI.begin(); - + // Disable unused Pins (for power saving) for (int i = 0; i < (sizeof(disabledPins) / sizeof(disabledPins[0])) - 1; i++) pinMode(disabledPins[i], INPUT_PULLUP); @@ -178,12 +206,25 @@ void setup() #endif // Setup LMIC + DEBUG_PRINT("Initializing LMIC...") os_init(); LMIC_reset(); // Reset LMIC state and cancel all queued transmissions LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100); // Compensate for Clock Skew LMIC.dn2Dr = DR_SF9; // Downlink Band LMIC_setDrTxpow(DR_SF7, 14); // Default to SF7 + DEBUG_PRINTLN("Done"); + // Check if Sending Interval is set in EEPROM + // if we get 65535 (0xFFFF) EEPROM was not written + uint16_t tmpsleep = 0; + EEPROM.get(ADDR_SLP, tmpsleep); + if (tmpsleep < 65535) { + DEBUG_PRINT("Setting Sleep Time from EEPROM to "); + DEBUG_PRINTLN(tmpsleep); + sleep_time = tmpsleep; + } + + DEBUG_PRINTLN("Setup Finished"); // Schedule First Send (Triggers OTAA Join as well) do_send(&sendjob);