diff --git a/platformio.ini b/platformio.ini index 478c23fb2a444a536e08088e10d96749bc6cda92..925298cc7ee1f9dcfc10d27ebd6fb480b55511eb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,3 +26,5 @@ lib_deps = TinyGPSPlus@1.0.2 MCCI Arduino LoRaWAN Library@0.8.0 OneButton@0.0.0-alpha+sha.eb583d713a + CayenneLPP@1.1.0 + diff --git a/src/main.cpp b/src/main.cpp index 3f531ce11fd5f351290bec442f956c27e313d290..11dce95ebfa2564858794b8eb7f15fe5f16af43b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,44 +5,43 @@ #include <hal/hal.h> #include <SPI.h> #include <TinyGPS++.h> +#include <CayenneLPP.h> #include <OneButton.h> class cLoRaWAN : public Arduino_LoRaWAN_ttn { public: - cLoRaWAN(){}; + cLoRaWAN(){}; protected: - virtual bool GetOtaaProvisioningInfo(Arduino_LoRaWAN::OtaaProvisioningInfo *) override; - virtual void NetSaveFCntUp(uint32_t uFCntUp) override; - virtual void NetSaveFCntDown(uint32_t uFCntDown) override; - virtual void NetSaveSessionInfo(const SessionInfo &Info, const uint8_t *pExtraInfo, size_t nExtraInfo) override; + virtual bool GetOtaaProvisioningInfo(Arduino_LoRaWAN::OtaaProvisioningInfo *) override; + virtual void NetSaveFCntUp(uint32_t uFCntUp) override; + virtual void NetSaveFCntDown(uint32_t uFCntDown) override; + virtual void NetSaveSessionInfo(const SessionInfo &Info, const uint8_t *pExtraInfo, size_t nExtraInfo) override; }; bool cLoRaWAN::GetOtaaProvisioningInfo( OtaaProvisioningInfo *pInfo) { - static const uint8_t DEVEUI[8] = TTN_DEVEUI; - static const uint8_t APPEUI[8] = TTN_APPEUI; - static const uint8_t APPKEY[16] = TTN_APPKEY; + static const uint8_t DEVEUI[8] = TTN_DEVEUI; + static const uint8_t APPEUI[8] = TTN_APPEUI; + static const uint8_t APPKEY[16] = TTN_APPKEY; - if (pInfo) - { - memcpy(pInfo->AppKey, APPKEY, sizeof(APPKEY)); - memcpy(pInfo->DevEUI, DEVEUI, sizeof(DEVEUI)); - memcpy(pInfo->AppEUI, APPEUI, sizeof(APPEUI)); - } - return true; + if (pInfo) + { + memcpy(pInfo->AppKey, APPKEY, sizeof(APPKEY)); + memcpy(pInfo->DevEUI, DEVEUI, sizeof(DEVEUI)); + memcpy(pInfo->AppEUI, APPEUI, sizeof(APPEUI)); + } + return true; } void cLoRaWAN::NetSaveFCntDown(uint32_t uFCntDown) { - // save uFcntDown somwwhere } void cLoRaWAN::NetSaveFCntUp(uint32_t uFCntUp) { - // save uFCntUp somewhere } void cLoRaWAN::NetSaveSessionInfo( @@ -50,7 +49,6 @@ void cLoRaWAN::NetSaveSessionInfo( const uint8_t *pExtraInfo, size_t nExtraInfo) { - // save Info somewhere. } const cLoRaWAN::lmic_pinmap pinMap = { @@ -64,233 +62,223 @@ AXP20X_Class axp; HardwareSerial GPS(1); TinyGPSPlus gps; cLoRaWAN LoRaWAN{}; +CayenneLPP lpp(55); +DynamicJsonDocument jsonBuffer(1024); OneButton btn = OneButton(BUTTON_PIN, true, true); +unsigned long statusTimer; -static uint8_t mydata[] = "Hello, world!"; -static osjob_t sendjob; -const unsigned TX_INTERVAL = 60; +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")); + 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")); + } + break; + case EV_LOST_TSYNC: + Serial.println(F("EV_LOST_TSYNC")); + break; + case EV_RESET: + Serial.println(F("EV_RESET")); + break; + case EV_RXCOMPLETE: + 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; + case EV_SCAN_FOUND: + Serial.println(F("EV_SCAN_FOUND")); + break; + case EV_TXSTART: + Serial.println(F("EV_TXSTART")); + break; + case EV_TXCANCELED: + Serial.println(F("EV_TXCANCELLED")); + break; + case EV_JOIN_TXCOMPLETE: + Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept")); + break; + default: + Serial.println(F("Unknown event " + (unsigned)ev)); + break; + } +} void setupPower() { - if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) - { - Serial.println("AXP192 Begin PASS"); - } - else - { - Serial.println("AXP192 Begin FAIL"); - } - axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); // OLED : off - axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); // N/C : off - axp.setPowerOutPut(AXP192_DCDC3, AXP202_ON); // ESP32 : on - axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA : on - axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS : on - axp.setDCDC3Voltage(3300); // ESP32 : 3.3V - axp.setLDO2Voltage(3300); // LORA : 3.3V - axp.setLDO3Voltage(3300); // GPS : 3.3V - axp.setChgLEDMode(AXP20X_LED_OFF); + if (!axp.begin(Wire, AXP192_SLAVE_ADDRESS)) + { + Serial.println("AXP192 Begin PASS"); + } + else + { + Serial.println("AXP192 Begin FAIL"); + } + axp.setPowerOutPut(AXP192_DCDC1, AXP202_OFF); // OLED : off + axp.setPowerOutPut(AXP192_DCDC2, AXP202_OFF); // N/C : off + axp.setPowerOutPut(AXP192_DCDC3, AXP202_ON); // ESP32 : on + axp.setPowerOutPut(AXP192_LDO2, AXP202_ON); // LORA : on + axp.setPowerOutPut(AXP192_LDO3, AXP202_ON); // GPS : on + axp.setDCDC3Voltage(3300); // ESP32 : 3.3V + axp.setLDO2Voltage(3300); // LORA : 3.3V + axp.setLDO3Voltage(3300); // GPS : 3.3V + axp.setChgLEDMode(AXP20X_LED_OFF); } void setupGps() { - GPS.begin(9600, SERIAL_8N1, 34, 12); // IO34: RX, IO12: TX + GPS.begin(9600, SERIAL_8N1, 34, 12); // IO34: RX, IO12: TX } void printStatus() { - axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); - while (GPS.available()) - { - gps.encode(GPS.read()); - } - Serial.println("##############################"); - Serial.println("--- Power ---"); - Serial.printf("DCDC1/OLED Status : %s\n", axp.isDCDC1Enable() ? "enabled" : "disabled"); - Serial.printf("DCDC1/OLED Voltage : %g V\n", (float)axp.getDCDC1Voltage() / 1000); - Serial.printf("DCDC2/N/C Status : %s\n", axp.isDCDC2Enable() ? "enabled" : "disabled"); - Serial.printf("DCDC2/N/C Voltage : %g V\n", (float)axp.getDCDC2Voltage() / 1000); - Serial.printf("DCDC3/ESP32 Status : %s\n", axp.isDCDC3Enable() ? "enabled" : "disabled"); - Serial.printf("DCDC3/ESP32 Voltage : %g V\n", (float)axp.getDCDC3Voltage() / 1000); - Serial.printf("LDO2/LoRa Status : %s\n", axp.isLDO2Enable() ? "enabled" : "disabled"); - Serial.printf("LDO2/LoRa Voltage : %g V\n", (float)axp.getLDO2Voltage() / 1000); - Serial.printf("LDO3/GPS Status : %s\n", axp.isLDO3Enable() ? "enabled" : "disabled"); - Serial.printf("LDO3/GPS Voltage : %g V\n", (float)axp.getLDO3Voltage() / 1000); - Serial.println("--- Battery ---"); - Serial.printf("Battery Connected: %s\n", axp.isBatteryConnect() ? "true" : "false"); - if (axp.isBatteryConnect()) - { - Serial.printf("Battery Percentage : %d %%\n", axp.getBattPercentage()); - Serial.printf("Battery Voltage : %g V\n", axp.getBattVoltage() / 1000); - Serial.printf("Charging Enabled : %s\n", axp.isChargeingEnable() ? "true" : "false"); - Serial.printf("Battery Charging : %s\n", axp.isChargeing() ? "true" : "false"); - Serial.printf("Set Charge Current : %g mA\n", axp.getSettingChargeCurrent()); - } - Serial.println("--- Chip ---"); - Serial.printf("Chip Temp : %.1f C°\n", axp.getTemp() / 10); - Serial.println("--- GPS ---"); - Serial.print("Latitude : "); - Serial.println(gps.location.lat(), 5); - Serial.print("Longitude : "); - Serial.println(gps.location.lng(), 4); - Serial.print("Satellites : "); - Serial.println(gps.satellites.value()); - Serial.print("Altitude : "); - Serial.print(gps.altitude.feet() / 3.2808); - Serial.println("M"); - Serial.print("Time : "); - Serial.print(gps.time.hour()); - Serial.print(":"); - Serial.print(gps.time.minute()); - Serial.print(":"); - Serial.println(gps.time.second()); - Serial.print("Speed : "); - Serial.println(gps.speed.kmph()); - Serial.println("##############################"); - axp.setChgLEDMode(AXP20X_LED_OFF); -} - -static void handleClick() { - printStatus(); -} - -void do_send(osjob_t *j) -{ - // 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, mydata, sizeof(mydata) - 1, 0); - Serial.println(F("Packet queued")); - } - // Next TX is scheduled after TX_COMPLETE event. + axp.setChgLEDMode(AXP20X_LED_LOW_LEVEL); + while (GPS.available()) + { + gps.encode(GPS.read()); + } + Serial.println("##############################"); + Serial.println("--- Power ---"); + Serial.printf("DCDC1/OLED Status : %s\n", axp.isDCDC1Enable() ? "enabled" : "disabled"); + Serial.printf("DCDC1/OLED Voltage : %g V\n", (float)axp.getDCDC1Voltage() / 1000); + Serial.printf("DCDC2/N/C Status : %s\n", axp.isDCDC2Enable() ? "enabled" : "disabled"); + Serial.printf("DCDC2/N/C Voltage : %g V\n", (float)axp.getDCDC2Voltage() / 1000); + Serial.printf("DCDC3/ESP32 Status : %s\n", axp.isDCDC3Enable() ? "enabled" : "disabled"); + Serial.printf("DCDC3/ESP32 Voltage : %g V\n", (float)axp.getDCDC3Voltage() / 1000); + Serial.printf("LDO2/LoRa Status : %s\n", axp.isLDO2Enable() ? "enabled" : "disabled"); + Serial.printf("LDO2/LoRa Voltage : %g V\n", (float)axp.getLDO2Voltage() / 1000); + Serial.printf("LDO3/GPS Status : %s\n", axp.isLDO3Enable() ? "enabled" : "disabled"); + Serial.printf("LDO3/GPS Voltage : %g V\n", (float)axp.getLDO3Voltage() / 1000); + Serial.println("--- Battery ---"); + Serial.printf("Battery Connected: %s\n", axp.isBatteryConnect() ? "true" : "false"); + if (axp.isBatteryConnect()) + { + Serial.printf("Battery Percentage : %d %%\n", axp.getBattPercentage()); + Serial.printf("Battery Percentage : %f %%\n", axp.getBattPercentage()); + Serial.printf("Battery Percentage : %g %%\n", axp.getBattPercentage()); + Serial.printf("Battery Voltage : %g V\n", axp.getBattVoltage() / 1000); + Serial.printf("Battery Current : %g mA\n", axp.getBattDischargeCurrent()); + Serial.println("--- Charging ---"); + Serial.printf("Charging Enabled : %s\n", axp.isChargeingEnable() ? "true" : "false"); + Serial.printf("Battery Charging : %s\n", axp.isChargeing() ? "true" : "false"); + Serial.printf("Set Charge Current : %g mA\n", axp.getSettingChargeCurrent()); + } + Serial.println("--- Chip ---"); + Serial.printf("Chip Temp : %.1f C°\n", axp.getTemp() / 10); + Serial.println("--- GPS ---"); + Serial.print("Latitude : "); + Serial.println(gps.location.lat(), 5); + Serial.print("Longitude : "); + Serial.println(gps.location.lng(), 4); + Serial.print("Satellites : "); + Serial.println(gps.satellites.value()); + Serial.print("Altitude : "); + Serial.print(gps.altitude.meters()); + Serial.println("M"); + Serial.print("Time : "); + Serial.print(gps.time.hour()); + Serial.print(":"); + Serial.print(gps.time.minute()); + Serial.print(":"); + Serial.println(gps.time.second()); + Serial.print("Speed : "); + Serial.println(gps.speed.kmph()); + Serial.println("##############################"); + axp.setChgLEDMode(AXP20X_LED_OFF); } -void onEvent(ev_t ev) +void do_send() { - 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")); - // TTN uses SF9 for its RX2 window. - LMIC.dn2Dr = EU868_DR_SF9; - break; - case EV_JOINED: - Serial.println(F("EV_JOINED")); + // Check if there is not a current TX/RX job running + if (LMIC.opmode & OP_TXRXPEND) { - u4_t netid = 0; - devaddr_t devaddr = 0; - u1_t nwkKey[16]; - u1_t artKey[16]; - LMIC_getSessionKeys(&netid, &devaddr, nwkKey, artKey); - Serial.print("netid: "); - Serial.println(netid, DEC); - Serial.print("devaddr: "); - Serial.println(devaddr, HEX); - Serial.print("artKey: "); - for (int i = 0; i < sizeof(artKey); ++i) - { - Serial.print(artKey[i], HEX); - } - Serial.println(""); - Serial.print("nwkKey: "); - for (int i = 0; i < sizeof(nwkKey); ++i) - { - Serial.print(nwkKey[i], HEX); - } - Serial.println(""); - - LMIC_setSeqnoUp(140); + Serial.println(F("OP_TXRXPEND, not sending")); } - 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) + else { - Serial.println(F("Received ")); - Serial.println(LMIC.dataLen); - Serial.println(F(" bytes of payload")); + while (GPS.available()) + { + gps.encode(GPS.read()); + } + lpp.reset(); + lpp.addGPS(1, gps.location.lat(), gps.location.lng(), gps.altitude.meters()); + lpp.addAnalogInput(2, axp.getBattVoltage()/1000); + LMIC_setTxData2(1, lpp.getBuffer(), lpp.getSize(), 0); + Serial.println(F("Packet queued")); + Serial.println(); + JsonObject json = jsonBuffer.to<JsonObject>(); + lpp.decodeTTN(lpp.getBuffer(), lpp.getSize(), json); + serializeJsonPretty(json, Serial); + Serial.println(); } - // Schedule next transmission - os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send); - 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; - case EV_SCAN_FOUND: - Serial.println(F("EV_SCAN_FOUND")); - break; - case EV_TXSTART: - Serial.println(F("EV_TXSTART")); - break; - case EV_TXCANCELED: - Serial.println(F("EV_TXCANCELLED")); - break; - case EV_JOIN_TXCOMPLETE: - Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept")); - break; - default: - Serial.println(F("Unknown event " + (unsigned)ev)); - break; - } +} + +static void handleClick() +{ + printStatus(); + do_send(); } void setup() { - Serial.begin(115200); - Wire.begin(21, 22); - setupPower(); - setupGps(); - LoRaWAN.begin(pinMap); - btn.attachClick(handleClick); - printStatus(); - do_send(&sendjob); + Serial.begin(115200); + Wire.begin(21, 22); + setupPower(); + setupGps(); + LoRaWAN.begin(pinMap); + btn.attachClick(handleClick); + printStatus(); + statusTimer = millis(); } void loop() { - LoRaWAN.loop(); - btn.tick(); + LoRaWAN.loop(); + btn.tick(); + if (millis() - statusTimer >= 1000 * 30) { + printStatus(); + do_send(); + statusTimer = millis(); + } }