#include <config.h> #include <axp20x.h> #include <Arduino_LoRaWAN_ttn.h> #include <lmic.h> #include <hal/hal.h> #include <SPI.h> #include <TinyGPS++.h> #include <CayenneLPP.h> #include <OneButton.h> class cLoRaWAN : public Arduino_LoRaWAN_ttn { public: 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; }; 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; 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) { } void cLoRaWAN::NetSaveFCntUp(uint32_t uFCntUp) { } void cLoRaWAN::NetSaveSessionInfo( const SessionInfo &Info, const uint8_t *pExtraInfo, size_t nExtraInfo) { } const cLoRaWAN::lmic_pinmap pinMap = { .nss = 18, .rxtx = cLoRaWAN::lmic_pinmap::LMIC_UNUSED_PIN, .rst = 23, .dio = {26, 33, cLoRaWAN::lmic_pinmap::LMIC_UNUSED_PIN}, }; 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; 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); } void setupGps() { 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("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 do_send() { // Check if there is not a current TX/RX job running if (LMIC.opmode & OP_TXRXPEND) { Serial.println(F("OP_TXRXPEND, not sending")); } else { 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(); } } static void handleClick() { printStatus(); do_send(); } void setup() { Serial.begin(115200); Wire.begin(21, 22); setupPower(); setupGps(); LoRaWAN.begin(pinMap); btn.attachClick(handleClick); printStatus(); statusTimer = millis(); } void loop() { LoRaWAN.loop(); btn.tick(); if (millis() - statusTimer >= 1000 * 30) { printStatus(); do_send(); statusTimer = millis(); } }