feat(firmware): 硬件联调引脚定义&远程启动充电和相关外设联动逻辑
This commit is contained in:
36
hardware/firmware/include/pins.h
Normal file
36
hardware/firmware/include/pins.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef HELIOS_PINS_H
|
||||||
|
#define HELIOS_PINS_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// Panel switches and LEDs
|
||||||
|
static const uint8_t PIN_CC1 = 39; // High-active switch
|
||||||
|
static const uint8_t PIN_CC2 = 36; // High-active switch
|
||||||
|
static const uint8_t PIN_LED1 = 32; // Low-active LED
|
||||||
|
static const uint8_t PIN_LED2 = 33; // Low-active LED
|
||||||
|
|
||||||
|
// Key inputs
|
||||||
|
static const uint8_t PIN_KEY1 = 34;
|
||||||
|
static const uint8_t PIN_KEY2 = 35;
|
||||||
|
|
||||||
|
// Relay outputs
|
||||||
|
static const uint8_t PIN_RELAY1 = 27;
|
||||||
|
static const uint8_t PIN_RELAY2 = 14;
|
||||||
|
|
||||||
|
// I2C (OLED)
|
||||||
|
static const uint8_t PIN_OLED_SCL = 22;
|
||||||
|
static const uint8_t PIN_OLED_SDA = 21;
|
||||||
|
|
||||||
|
// SPI (RC522)
|
||||||
|
static const uint8_t PIN_RC_MOSI = 23;
|
||||||
|
static const uint8_t PIN_RC_MISO = 19;
|
||||||
|
static const uint8_t PIN_RC_SCK = 18;
|
||||||
|
static const uint8_t PIN_RC_CS = 5;
|
||||||
|
static const uint8_t PIN_RC_RST = 4;
|
||||||
|
|
||||||
|
// UART2 <-> IM1281C (U2)
|
||||||
|
static const uint8_t PIN_U2TXD = 26;
|
||||||
|
static const uint8_t PIN_U2RXD = 25;
|
||||||
|
static const uint32_t BAUD_IM1281C = 9600;
|
||||||
|
|
||||||
|
#endif // HELIOS_PINS_H
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
|
#include <SPI.h>
|
||||||
#include <WiFiManager.h>
|
#include <WiFiManager.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -14,6 +15,7 @@
|
|||||||
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "pins.h"
|
||||||
|
|
||||||
/* LED State Enum */
|
/* LED State Enum */
|
||||||
enum LEDState
|
enum LEDState
|
||||||
@@ -32,6 +34,27 @@ static volatile LEDState s_led_state = LED_INITIALIZING;
|
|||||||
static volatile unsigned long s_blink_last_time = 0;
|
static volatile unsigned long s_blink_last_time = 0;
|
||||||
static volatile bool s_blink_on = false;
|
static volatile bool s_blink_on = false;
|
||||||
static const unsigned long BLINK_INTERVAL = 200; // 200ms blink interval
|
static const unsigned long BLINK_INTERVAL = 200; // 200ms blink interval
|
||||||
|
static const unsigned long CC_DEBOUNCE_MS = 30;
|
||||||
|
static const unsigned long AUTH_WINDOW_MS = 30000;
|
||||||
|
|
||||||
|
static bool s_cc1_plugged = false;
|
||||||
|
static bool s_cc2_plugged = false;
|
||||||
|
static bool s_cc1_raw_last = false;
|
||||||
|
static bool s_cc2_raw_last = false;
|
||||||
|
static unsigned long s_cc1_last_change_ms = 0;
|
||||||
|
static unsigned long s_cc2_last_change_ms = 0;
|
||||||
|
static bool s_cc1_prev_plugged = false;
|
||||||
|
static bool s_cc2_prev_plugged = false;
|
||||||
|
|
||||||
|
static bool s_key1_prev = false;
|
||||||
|
static bool s_key2_prev = false;
|
||||||
|
|
||||||
|
static bool s_auth_in_progress = false;
|
||||||
|
static bool s_auth_ok = false;
|
||||||
|
static unsigned long s_auth_ok_at_ms = 0;
|
||||||
|
static String s_auth_id_tag;
|
||||||
|
|
||||||
|
static bool s_remote_start_accepted = false;
|
||||||
|
|
||||||
uint8_t mac[6];
|
uint8_t mac[6];
|
||||||
char cpSerial[13];
|
char cpSerial[13];
|
||||||
@@ -62,6 +85,205 @@ Adafruit_SSD1306 display(128, 64, &Wire, -1);
|
|||||||
#define LED_COUNT 1
|
#define LED_COUNT 1
|
||||||
|
|
||||||
SmartLed leds(LED_WS2812B, LED_COUNT, LED_PIN, 0, DoubleBuffer);
|
SmartLed leds(LED_WS2812B, LED_COUNT, LED_PIN, 0, DoubleBuffer);
|
||||||
|
MFRC522 rfid(PIN_RC_CS, PIN_RC_RST);
|
||||||
|
|
||||||
|
static bool isConnectorPlugged(unsigned int connectorId)
|
||||||
|
{
|
||||||
|
if (connectorId == 1)
|
||||||
|
return s_cc1_plugged;
|
||||||
|
if (connectorId == 2)
|
||||||
|
return s_cc2_plugged;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isConnectorIdle(unsigned int connectorId)
|
||||||
|
{
|
||||||
|
return !isTransactionActive(connectorId) && !isTransactionRunning(connectorId) && !getTransaction(connectorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isConnectorStartReady(unsigned int connectorId)
|
||||||
|
{
|
||||||
|
return connectorId >= 1 && connectorId <= 2 && isOperative(connectorId) && isConnectorIdle(connectorId) && isConnectorPlugged(connectorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateConnectorPluggedState()
|
||||||
|
{
|
||||||
|
unsigned long now = millis();
|
||||||
|
|
||||||
|
const bool cc1_raw = (digitalRead(PIN_CC1) == HIGH);
|
||||||
|
if (cc1_raw != s_cc1_raw_last)
|
||||||
|
{
|
||||||
|
s_cc1_raw_last = cc1_raw;
|
||||||
|
s_cc1_last_change_ms = now;
|
||||||
|
}
|
||||||
|
if ((now - s_cc1_last_change_ms) >= CC_DEBOUNCE_MS)
|
||||||
|
{
|
||||||
|
s_cc1_plugged = s_cc1_raw_last;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool cc2_raw = (digitalRead(PIN_CC2) == HIGH);
|
||||||
|
if (cc2_raw != s_cc2_raw_last)
|
||||||
|
{
|
||||||
|
s_cc2_raw_last = cc2_raw;
|
||||||
|
s_cc2_last_change_ms = now;
|
||||||
|
}
|
||||||
|
if ((now - s_cc2_last_change_ms) >= CC_DEBOUNCE_MS)
|
||||||
|
{
|
||||||
|
s_cc2_plugged = s_cc2_raw_last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updatePanelLedsFromPlugState()
|
||||||
|
{
|
||||||
|
// Reserved for startup sync; runtime LED behavior is tied to charging permission.
|
||||||
|
digitalWrite(PIN_LED1, HIGH);
|
||||||
|
digitalWrite(PIN_LED2, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateChargeActuators()
|
||||||
|
{
|
||||||
|
const bool chg1_on = ocppPermitsCharge(1);
|
||||||
|
const bool chg2_on = ocppPermitsCharge(2);
|
||||||
|
|
||||||
|
// LEDs and relays are low-active
|
||||||
|
digitalWrite(PIN_LED1, chg1_on ? LOW : HIGH);
|
||||||
|
digitalWrite(PIN_LED2, chg2_on ? LOW : HIGH);
|
||||||
|
digitalWrite(PIN_RELAY1, chg1_on ? LOW : HIGH);
|
||||||
|
digitalWrite(PIN_RELAY2, chg2_on ? LOW : HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stopIfUnplugged()
|
||||||
|
{
|
||||||
|
if (s_cc1_prev_plugged && !s_cc1_plugged && (isTransactionActive(1) || isTransactionRunning(1)))
|
||||||
|
{
|
||||||
|
Serial.println("[main] Connector 1 unplugged. Stop transaction immediately.");
|
||||||
|
endTransaction(nullptr, "EVDisconnected", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_cc2_prev_plugged && !s_cc2_plugged && (isTransactionActive(2) || isTransactionRunning(2)))
|
||||||
|
{
|
||||||
|
Serial.println("[main] Connector 2 unplugged. Stop transaction immediately.");
|
||||||
|
endTransaction(nullptr, "EVDisconnected", 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_cc1_prev_plugged = s_cc1_plugged;
|
||||||
|
s_cc2_prev_plugged = s_cc2_plugged;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool authWindowValid()
|
||||||
|
{
|
||||||
|
return s_auth_ok && (millis() - s_auth_ok_at_ms) <= AUTH_WINDOW_MS && s_auth_id_tag.length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void requestAuthorizeByCard(const String &idTag)
|
||||||
|
{
|
||||||
|
if (s_auth_in_progress)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_auth_in_progress = true;
|
||||||
|
s_auth_ok = false;
|
||||||
|
s_auth_id_tag = "";
|
||||||
|
|
||||||
|
Serial.printf("[main] Authorize idTag: %s\n", idTag.c_str());
|
||||||
|
authorize(
|
||||||
|
idTag.c_str(),
|
||||||
|
[idTag](JsonObject payload)
|
||||||
|
{
|
||||||
|
s_auth_in_progress = false;
|
||||||
|
const char *status = payload["idTagInfo"]["status"] | "";
|
||||||
|
if (!strcmp(status, "Accepted"))
|
||||||
|
{
|
||||||
|
s_auth_ok = true;
|
||||||
|
s_auth_ok_at_ms = millis();
|
||||||
|
s_auth_id_tag = idTag;
|
||||||
|
Serial.printf("[main] Authorize accepted for idTag %s\n", idTag.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_auth_ok = false;
|
||||||
|
s_auth_id_tag = "";
|
||||||
|
Serial.printf("[main] Authorize rejected, status=%s\n", status);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[]()
|
||||||
|
{
|
||||||
|
s_auth_in_progress = false;
|
||||||
|
s_auth_ok = false;
|
||||||
|
s_auth_id_tag = "";
|
||||||
|
Serial.println("[main] Authorize aborted");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pollRfidCard()
|
||||||
|
{
|
||||||
|
if (!rfid.PICC_IsNewCardPresent() || !rfid.PICC_ReadCardSerial())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String idTag;
|
||||||
|
for (byte i = 0; i < rfid.uid.size; i++)
|
||||||
|
{
|
||||||
|
if (rfid.uid.uidByte[i] < 0x10)
|
||||||
|
{
|
||||||
|
idTag += '0';
|
||||||
|
}
|
||||||
|
idTag += String(rfid.uid.uidByte[i], HEX);
|
||||||
|
}
|
||||||
|
idTag.toUpperCase();
|
||||||
|
|
||||||
|
rfid.PICC_HaltA();
|
||||||
|
rfid.PCD_StopCrypto1();
|
||||||
|
|
||||||
|
requestAuthorizeByCard(idTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tryStartByKey(unsigned int connectorId)
|
||||||
|
{
|
||||||
|
if (!authWindowValid())
|
||||||
|
{
|
||||||
|
Serial.println("[main] No valid authorization window. Swipe card first.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isConnectorStartReady(connectorId))
|
||||||
|
{
|
||||||
|
Serial.printf("[main] Connector %u not ready for start (needs idle + operative + plugged).\n", connectorId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tx = beginTransaction_authorized(s_auth_id_tag.c_str(), nullptr, connectorId);
|
||||||
|
if (tx)
|
||||||
|
{
|
||||||
|
Serial.printf("[main] Local start accepted on connector %u for idTag %s\n", connectorId, s_auth_id_tag.c_str());
|
||||||
|
s_auth_ok = false;
|
||||||
|
s_auth_id_tag = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.printf("[main] Local start failed on connector %u\n", connectorId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pollStartKeys()
|
||||||
|
{
|
||||||
|
const bool key1 = (digitalRead(PIN_KEY1) == HIGH);
|
||||||
|
const bool key2 = (digitalRead(PIN_KEY2) == HIGH);
|
||||||
|
|
||||||
|
if (key1 && !s_key1_prev)
|
||||||
|
{
|
||||||
|
tryStartByKey(1);
|
||||||
|
}
|
||||||
|
if (key2 && !s_key2_prev)
|
||||||
|
{
|
||||||
|
tryStartByKey(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
s_key1_prev = key1;
|
||||||
|
s_key2_prev = key2;
|
||||||
|
}
|
||||||
|
|
||||||
/* LED Control Functions */
|
/* LED Control Functions */
|
||||||
void updateLED()
|
void updateLED()
|
||||||
@@ -175,11 +397,38 @@ void setup()
|
|||||||
s_blink_last_time = 0;
|
s_blink_last_time = 0;
|
||||||
s_blink_on = false;
|
s_blink_on = false;
|
||||||
|
|
||||||
|
// Initialize CC switches (input) and panel LEDs (low-active output)
|
||||||
|
pinMode(PIN_CC1, INPUT);
|
||||||
|
pinMode(PIN_CC2, INPUT);
|
||||||
|
pinMode(PIN_KEY1, INPUT);
|
||||||
|
pinMode(PIN_KEY2, INPUT);
|
||||||
|
pinMode(PIN_LED1, OUTPUT);
|
||||||
|
pinMode(PIN_LED2, OUTPUT);
|
||||||
|
pinMode(PIN_RELAY1, OUTPUT);
|
||||||
|
pinMode(PIN_RELAY2, OUTPUT);
|
||||||
|
digitalWrite(PIN_LED1, HIGH); // Off by default (low-active)
|
||||||
|
digitalWrite(PIN_LED2, HIGH); // Off by default (low-active)
|
||||||
|
digitalWrite(PIN_RELAY1, HIGH); // Off by default (low-active)
|
||||||
|
digitalWrite(PIN_RELAY2, HIGH); // Off by default (low-active)
|
||||||
|
updateConnectorPluggedState();
|
||||||
|
updatePanelLedsFromPlugState();
|
||||||
|
|
||||||
leds[0] = Rgb{255, 255, 0};
|
leds[0] = Rgb{255, 255, 0};
|
||||||
leds.show();
|
leds.show();
|
||||||
|
|
||||||
// Initialize IIC OLED
|
// Initialize I2C for OLED (from schematic pin map)
|
||||||
Wire.begin(4, 15);
|
Wire.begin(PIN_OLED_SDA, PIN_OLED_SCL);
|
||||||
|
|
||||||
|
// Initialize UART2 for IM1281C (U2)
|
||||||
|
Serial2.begin(BAUD_IM1281C, SERIAL_8N1, PIN_U2RXD, PIN_U2TXD);
|
||||||
|
|
||||||
|
// Initialize SPI bus for RC522
|
||||||
|
SPI.begin(PIN_RC_SCK, PIN_RC_MISO, PIN_RC_MOSI, PIN_RC_CS);
|
||||||
|
pinMode(PIN_RC_CS, OUTPUT);
|
||||||
|
digitalWrite(PIN_RC_CS, HIGH);
|
||||||
|
pinMode(PIN_RC_RST, OUTPUT);
|
||||||
|
digitalWrite(PIN_RC_RST, HIGH);
|
||||||
|
rfid.PCD_Init();
|
||||||
|
|
||||||
// Load configuration from Preferences
|
// Load configuration from Preferences
|
||||||
Preferences preferences;
|
Preferences preferences;
|
||||||
@@ -410,6 +659,80 @@ void setup()
|
|||||||
|
|
||||||
mocpp_initialize(*client, ChargerCredentials(CFG_CP_MODAL, CFG_CP_VENDOR, CFG_CP_FW_VERSION, cpSerial, nullptr, nullptr, CFG_CB_SERIAL, nullptr, nullptr), MicroOcpp::makeDefaultFilesystemAdapter(MicroOcpp::FilesystemOpt::Use_Mount_FormatOnFail));
|
mocpp_initialize(*client, ChargerCredentials(CFG_CP_MODAL, CFG_CP_VENDOR, CFG_CP_FW_VERSION, cpSerial, nullptr, nullptr, CFG_CB_SERIAL, nullptr, nullptr), MicroOcpp::makeDefaultFilesystemAdapter(MicroOcpp::FilesystemOpt::Use_Mount_FormatOnFail));
|
||||||
|
|
||||||
|
// Expose both physical connectors to CSMS and feed live plug-state from CC switches.
|
||||||
|
// connectorId 1 <-> CC1, connectorId 2 <-> CC2
|
||||||
|
setConnectorPluggedInput([]()
|
||||||
|
{ return s_cc1_plugged; },
|
||||||
|
1);
|
||||||
|
setConnectorPluggedInput([]()
|
||||||
|
{ return s_cc2_plugged; },
|
||||||
|
2);
|
||||||
|
|
||||||
|
// Occupied state drives StatusNotification (Available <-> Preparing/Finishing)
|
||||||
|
// to report plug-in / unplug events even without an active transaction.
|
||||||
|
setOccupiedInput([]()
|
||||||
|
{ return s_cc1_plugged; },
|
||||||
|
1);
|
||||||
|
setOccupiedInput([]()
|
||||||
|
{ return s_cc2_plugged; },
|
||||||
|
2);
|
||||||
|
|
||||||
|
// Custom RemoteStartTransaction policy:
|
||||||
|
// accept only when target connector is idle + operative + plugged.
|
||||||
|
setRequestHandler(
|
||||||
|
"RemoteStartTransaction",
|
||||||
|
[](JsonObject payload)
|
||||||
|
{
|
||||||
|
s_remote_start_accepted = false;
|
||||||
|
|
||||||
|
const char *idTag = payload["idTag"] | "";
|
||||||
|
if (!idTag || !*idTag)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int reqConnectorId = payload["connectorId"] | -1;
|
||||||
|
unsigned int targetConnector = 0;
|
||||||
|
|
||||||
|
if (reqConnectorId >= 1 && reqConnectorId <= 2)
|
||||||
|
{
|
||||||
|
if (isConnectorStartReady((unsigned int)reqConnectorId))
|
||||||
|
{
|
||||||
|
targetConnector = (unsigned int)reqConnectorId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (unsigned int cid = 1; cid <= 2; cid++)
|
||||||
|
{
|
||||||
|
if (isConnectorStartReady(cid))
|
||||||
|
{
|
||||||
|
targetConnector = cid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetConnector == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tx = beginTransaction_authorized(idTag, nullptr, targetConnector);
|
||||||
|
s_remote_start_accepted = (tx != nullptr);
|
||||||
|
if (s_remote_start_accepted)
|
||||||
|
{
|
||||||
|
Serial.printf("[main] Remote start accepted on connector %u\n", targetConnector);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[]() -> std::unique_ptr<MicroOcpp::JsonDoc>
|
||||||
|
{
|
||||||
|
auto doc = std::unique_ptr<MicroOcpp::JsonDoc>(new MicroOcpp::JsonDoc(JSON_OBJECT_SIZE(1)));
|
||||||
|
JsonObject payload = doc->to<JsonObject>();
|
||||||
|
payload["status"] = s_remote_start_accepted ? "Accepted" : "Rejected";
|
||||||
|
return doc;
|
||||||
|
});
|
||||||
|
|
||||||
// For development/recovery: Set up BOOT button (GPIO 0)
|
// For development/recovery: Set up BOOT button (GPIO 0)
|
||||||
pinMode(0, INPUT_PULLUP);
|
pinMode(0, INPUT_PULLUP);
|
||||||
|
|
||||||
@@ -417,16 +740,27 @@ void setup()
|
|||||||
setOnSendConf("RemoteStopTransaction", [](JsonObject payload)
|
setOnSendConf("RemoteStopTransaction", [](JsonObject payload)
|
||||||
{
|
{
|
||||||
if (!strcmp(payload["status"], "Rejected")) {
|
if (!strcmp(payload["status"], "Rejected")) {
|
||||||
Serial.println("[main] MicroOcpp rejected RemoteStopTransaction! Force overriding and stopping charging...");
|
unsigned int connectorId = payload["connectorId"] | 1;
|
||||||
endTransaction(nullptr, "Remote", 1);
|
if (connectorId < 1 || connectorId > 2)
|
||||||
|
{
|
||||||
|
connectorId = 1;
|
||||||
|
}
|
||||||
|
Serial.printf("[main] MicroOcpp rejected RemoteStopTransaction on connector %u. Force overriding and stopping charging...\n", connectorId);
|
||||||
|
endTransaction(nullptr, "Remote", connectorId);
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
updateConnectorPluggedState();
|
||||||
|
stopIfUnplugged();
|
||||||
|
pollRfidCard();
|
||||||
|
pollStartKeys();
|
||||||
|
|
||||||
mg_mgr_poll(&mgr, 10);
|
mg_mgr_poll(&mgr, 10);
|
||||||
mocpp_loop();
|
mocpp_loop();
|
||||||
|
updateChargeActuators();
|
||||||
|
|
||||||
// Handle BOOT button (GPIO 0) interactions for recovery
|
// Handle BOOT button (GPIO 0) interactions for recovery
|
||||||
bool is_btn_pressed = (digitalRead(0) == LOW);
|
bool is_btn_pressed = (digitalRead(0) == LOW);
|
||||||
@@ -485,8 +819,9 @@ void loop()
|
|||||||
}
|
}
|
||||||
else if (held_time >= 3000)
|
else if (held_time >= 3000)
|
||||||
{
|
{
|
||||||
Serial.println("BOOT button held for > 3s! Forcefully ending dangling transaction...");
|
Serial.println("BOOT button held for > 3s! Forcefully ending dangling transactions on connector 1 and 2...");
|
||||||
endTransaction(nullptr, "PowerLoss", 1);
|
endTransaction(nullptr, "PowerLoss", 1);
|
||||||
|
endTransaction(nullptr, "PowerLoss", 2);
|
||||||
}
|
}
|
||||||
boot_was_pressed = false;
|
boot_was_pressed = false;
|
||||||
// Temporarily set to init so the logic below restores the actual network state accurately
|
// Temporarily set to init so the logic below restores the actual network state accurately
|
||||||
|
|||||||
Reference in New Issue
Block a user