From 22df5b1e3387b634e1680b8326b24163526cf31c Mon Sep 17 00:00:00 2001 From: Nigreon Date: Tue, 30 Dec 2025 22:41:30 +0100 Subject: [PATCH] First commit --- platformio.ini | 16 ++ src/lcdcrystal.ino | 648 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 664 insertions(+) create mode 100644 platformio.ini create mode 100644 src/lcdcrystal.ino diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..410fe5d --- /dev/null +++ b/platformio.ini @@ -0,0 +1,16 @@ +[platformio] +default_envs = pico + +[env:pico] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git +lib_deps = marcoschwartz/LiquidCrystal_I2C + fastled/FastLED + tedtoal/msToString + jakkapan-a/TcBUTTON + mprograms/SimpleRotary +# forntoh/LcdMenu +board = waveshare_rp2040_zero +framework = arduino +board_build.core = earlephilhower +targets = upload, monitor +monitor_filters = time diff --git a/src/lcdcrystal.ino b/src/lcdcrystal.ino new file mode 100644 index 0000000..0bd9991 --- /dev/null +++ b/src/lcdcrystal.ino @@ -0,0 +1,648 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +CRGB wsled[1]; + +#define PIN_SEND 2 +#define PIN_RECEIVE 3 +#define SENSORID 103 +#define PIN_LED 7 +#define PIN_RELAY 8 +#define PIN_SWITCH 6 +#define PIN_ENCODER_A 9 +#define PIN_ENCODER_B 10 +#define PIN_ENCODER_SW 11 + +const uint8_t encryptKey[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10 }; + +Speck cipher; +//AES128 cipher; + +RH_ASK radio(2000, PIN_RECEIVE, PIN_SEND, -1, false); + +RHEncryptedDriver driver (radio, cipher); + +LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display +CharacterDisplayRenderer renderer(new LiquidCrystal_I2CAdapter(&lcd), 20, 4, 0x7E, 0x7F); +LcdMenu menu(renderer); +KeyboardAdapter keyboard(&menu, &Serial); + +TcBUTTON button(PIN_SWITCH); +TcBUTTON encbutton(PIN_ENCODER_SW); + +SimpleRotary encoder(PIN_ENCODER_A, PIN_ENCODER_B, PIN_ENCODER_SW); + +//#define PZEM_004T +PZEM004T pzem(Serial1); + +uint32_t lastrefreshdisp; +uint32_t lasttransmit; + +char S[10]; + +struct config_t { + uint8_t initok; + bool state; + bool pstate; + uint16_t lcdsleep; + bool transmit_enabled; + uint16_t transmitinterval; + uint16_t tempm; + uint16_t tempp; + bool wattm_enabled; + bool wattp_enabled; + uint16_t wattm; + uint16_t wattp; + uint32_t counter_all; + uint32_t counter_used; +}; + +struct mmss_t { + uint16_t minute; + uint16_t second; +}; +struct hhmm_t { + uint16_t hour; + uint16_t minute; +}; + +struct conftemp_t { + bool tempm_enabled; + bool tempp_enabled; + uint32_t tempm; + uint32_t tempp; +}; + +struct measure_t { + uint16_t count; + uint16_t voltage; + uint32_t current; + uint32_t power; + uint32_t energy; + uint16_t pf; +}; + +uint8_t rh_payload[17]; + +struct mmss_t lcdsleep; +struct mmss_t transmitinterval; + +struct hhmm_t tempm; +struct hhmm_t tempp; + +uint32_t counter; + +struct conftemp_t conftemp; + +struct measure_t measure_lcd; +struct measure_t measure_t433; + +bool measure_lcd_reset; +bool measure_t433_reset; +bool measure_kwh_reset; + +struct config_t config; +bool ledblinkstate; + +bool menu_state; +bool lcdsleep_state; +uint32_t lastbuttonactivity; + +void load_config(); +void init_config(bool firststart); +void save_config(); +void reset_time(); +void reset_watt(); +void reset_all(); +void exit_menu(); +void PowerOff(); +void PowerOn(); +void refresh_display(); +void refresh_values(); +void refresh_counters(); +void refresh_confdisplay(); + +MENU_SCREEN(actionsScreen, actionsItems, + ITEM_BOOL_REF("Etat persist", config.pstate, "Oui", "Non", [](const Ref value) { config.pstate = value; save_config(); }, "%s"), + ITEM_BOOL_REF("T433", config.transmit_enabled, "Oui", "Non", [](const Ref value) { config.transmit_enabled = value; save_config(); }, "%s"), + ITEM_BOOL_REF("Watt-", config.wattm_enabled, "Oui", "Non", [](const Ref value) { config.wattm_enabled = value; save_config(); }, "%s"), + ITEM_BOOL_REF("Watt+", config.wattp_enabled, "Oui", "Non", [](const Ref value) { config.wattp_enabled = value; save_config(); }, "%s"), + ITEM_BOOL_REF("Tempo avant(-)", conftemp.tempm_enabled, "Oui", "Non", [](const Ref value) { conftemp.tempm_enabled = value; conftemp.tempm = config.tempm*60; if(value) { PowerOff(); } }, "%s"), + ITEM_BOOL_REF("Tempo apres(+)", conftemp.tempp_enabled, "Oui", "Non", [](const Ref value) { conftemp.tempp_enabled = value; conftemp.tempp = config.tempp*60; }, "%s")); +MENU_SCREEN(settingsScreen, settingsItems, + ITEM_RANGE_REF("Watt-", config.wattm, 1, 10, 3670, [](const Ref value) { config.wattm = value; save_config(); }, "%04dW"), + ITEM_RANGE_REF("Watt+", config.wattp, 1, 20, 3680, [](const Ref value) { config.wattp = value; save_config(); }, "%04dW"), + ITEM_WIDGET( + "Ecran(mm:ss)", + [](const Ref minute, const Ref second) { config.lcdsleep = minute*60+second; save_config(); }, + WIDGET_RANGE_REF(lcdsleep.minute, 1, 0, 59, "%02d", 0, false), + WIDGET_RANGE_REF(lcdsleep.second, 1, 0, 59, ":%02d", 0, false)), + ITEM_WIDGET( + "T433(mm:ss)", + [](const Ref minute, const Ref second) { config.transmitinterval = minute*60+second; save_config(); }, + WIDGET_RANGE_REF(transmitinterval.minute, 1, 0, 4, "%02d", 0, false), + WIDGET_RANGE_REF(transmitinterval.second, 1, 0, 59, ":%02d", 0, false)), + ITEM_WIDGET( + "Temp-(hh:mm)", + [](const Ref hour, const Ref minute) { config.tempm = hour*60+minute; save_config(); }, + WIDGET_RANGE_REF(tempm.hour, 1, 0, 23, "%02d", 0, false), + WIDGET_RANGE_REF(tempm.minute, 1, 0, 59, ":%02d", 0, false)), + ITEM_WIDGET( + "Temp+(hh:mm)", + [](const Ref hour, const Ref minute) { config.tempp = hour*60+minute; save_config(); }, + WIDGET_RANGE_REF(tempp.hour, 1, 0, 23, "%02d", 0, false), + WIDGET_RANGE_REF(tempp.minute, 1, 0, 59, ":%02d", 0, false))); +MENU_SCREEN(resetScreen, resetItems, + ITEM_COMMAND("Reset temps+kWh", []() { reset_all(); }), + ITEM_COMMAND("Reset temps", []() { reset_time(); }), + ITEM_COMMAND("Reset kWh", []() { reset_watt(); }), + ITEM_COMMAND("Reset conf. usine", []() { init_config(false); }) + ); +MENU_SCREEN(mainScreen, mainItems, + ITEM_SUBMENU("Actions", actionsScreen), + ITEM_SUBMENU("Reglages", settingsScreen), + ITEM_SUBMENU("Reset", resetScreen), + ITEM_COMMAND("Sortir du menu", []() { exit_menu(); })); + +void exit_menu() { + lastbuttonactivity=millis(); + menu_state=false; + save_config(); + menu.hide(); + refresh_display(); + refresh_counters(); + refresh_confdisplay(); +} + +void save_config() { + EEPROM.put(0, config); + EEPROM.commit(); +} + +void init_config(bool firststart) { + config.initok = 42; + config.state = false; + config.pstate = false; + config.lcdsleep = 60; + config.transmit_enabled = true; + config.transmitinterval = 15; + config.wattm_enabled = false; + config.wattp_enabled = false; + config.wattm = 100; + config.wattp = 2000; + config.tempm = 60; + config.tempp = 720; + if(firststart) { + config.counter_all = 0; + config.counter_used = 0; + } + save_config(); + load_config(); +} + +void load_config() { + EEPROM.get(0, config); + lcdsleep.minute = config.lcdsleep / 60; + lcdsleep.second = config.lcdsleep % 60; + transmitinterval.minute = config.transmitinterval / 60; + transmitinterval.second = config.transmitinterval % 60; + tempm.hour = config.tempm / 60; + tempm.minute = config.tempm % 60; + tempp.hour = config.tempp / 60; + tempp.minute = config.tempp % 60; +} + +void reset_time() { + config.counter_all=0; + config.counter_used=0; +} +void reset_watt() { + measure_kwh_reset = true; +} +void reset_all() { + reset_time(); + reset_watt(); +} + +void clear_lcd_temp() { + if(menu_state == false) { + lcd.setCursor(3, 3); + lcd.print(" "); + } +} + +void PowerOn() { + config.state=true; + conftemp.tempm_enabled = false; + clear_lcd_temp(); + refresh_confdisplay(); + save_config(); + digitalWrite(PIN_LED, HIGH); + digitalWrite(PIN_RELAY, HIGH); +} + +void PowerOff() { + config.state=false; + conftemp.tempp_enabled = false; + clear_lcd_temp(); + refresh_confdisplay(); + measure_lcd_reset = true; + measure_t433_reset = true; + save_config(); + digitalWrite(PIN_LED, LOW); + digitalWrite(PIN_RELAY, LOW); +} + +char* create_value(uint32_t value, char *ret, String unit, uint8_t factor, uint8_t factor2, uint8_t maxchar) { + char valuestr[10]; + ret[0]='\0'; + dtostrf(value/pow(10,factor2), maxchar, factor, valuestr); + if(strlen(valuestr) < maxchar) { + for(int i=0;i 0) { + conftemp.tempm--; + } else { + conftemp.tempm = config.tempm*60; + PowerOn(); + } + } + if(conftemp.tempp_enabled == true && config.state == true) { + if(conftemp.tempp > 0) { + conftemp.tempp--; + } else { + conftemp.tempp = config.tempp*60; + PowerOff(); + } + } + if(menu_state == false) { + refresh_values(); + refresh_temp(); + if(config.state) { refresh_counters(); } + } +} + +char confdisplay_char(char c, bool b) { + return b?c:'-'; +} + +void refresh_confdisplay() { + if(menu_state == false) { + char confdisplay[5]; + sprintf(confdisplay, "%c%c%c%c%c", confdisplay_char('w', config.wattm_enabled), confdisplay_char('W', config.wattp_enabled), confdisplay_char('t', conftemp.tempm_enabled), confdisplay_char('T', conftemp.tempp_enabled), confdisplay_char('X', config.transmit_enabled)); + lcd.setCursor(15, 3); + lcd.print(confdisplay); + } +} + +void blink() { + wsled[0] = CRGB::Red; FastLED.show(); + delay(100); + wsled[0] = CRGB::Black; FastLED.show(); +} + +void setSensorType(uint8_t stype) +{ + uint8_t payload0; + payload0 = stype << 4; + rh_payload[0] &= 0b00001111; + rh_payload[0] += payload0; +} + +void printHex(uint8_t num) { + char hexCar[2]; + + sprintf(hexCar, "%02X", num); + Serial.print(hexCar); +} + +void transmit() { + Serial.println("Transmit"); + //blink(); + + if(config.state == true) { + rh_payload[0] |= 0b00000001; + } else { + rh_payload[0] &= 0b11111110; + } + rh_payload[1] = measure_t433.voltage >> 8; + rh_payload[2] = measure_t433.voltage; + rh_payload[3] = measure_t433.current >> 24; + rh_payload[4] = measure_t433.current >> 16; + rh_payload[5] = measure_t433.current >> 8; + rh_payload[6] = measure_t433.current; + rh_payload[7] = measure_t433.power >> 24; + rh_payload[8] = measure_t433.power >> 16; + rh_payload[9] = measure_t433.power >> 8; + rh_payload[10] = measure_t433.power; + rh_payload[11] = measure_t433.energy >> 24; + rh_payload[12] = measure_t433.energy >> 16; + rh_payload[13] = measure_t433.energy >> 8; + rh_payload[14] = measure_t433.energy; + rh_payload[15] = measure_t433.pf >> 8; + rh_payload[16] = measure_t433.pf; + + measure_t433_reset = true; + + Serial.print("Hex RH Payload: "); + for(int i=0;i<17;i++) { + printHex(rh_payload[i]); + } + Serial.println(); + + driver.send(rh_payload, 17); + driver.waitPacketSent(); +} + +void onHoldButton() { + Serial.println("Button Held for 2 seconds!"); + if(lcdsleep_state == false) { + lastbuttonactivity=millis(); + } else { + reset_all(); + } +} + +void onPressButton() { + lastbuttonactivity=millis(); + if(lcdsleep_state) { + lcd.backlight(); + lcd.display(); + } else { + //Power + } +} + +void onPressEncButton() { + lastbuttonactivity=millis(); + if(lcdsleep_state) { + lcd.backlight(); + lcd.display(); + } else { + menu_state = true; + menu.show(); + } +} + +void setup() +{ + pinMode(PIN_LED, OUTPUT_12MA); + digitalWrite(PIN_LED, LOW); + pinMode(PIN_RELAY, OUTPUT_12MA); + digitalWrite(PIN_RELAY, LOW); + Serial.begin(); + FastLED.addLeds(wsled, 1); + EEPROM.begin(256); + delay(500); + if (!driver.init()) { Serial.println("RH init failed"); } + driver.setHeaderId(SENSORID); + cipher.setKey(encryptKey, sizeof(encryptKey)); + setSensorType(3); + load_config(); + conftemp.tempm_enabled = false; + conftemp.tempp_enabled = false; + conftemp.tempm = config.tempm*60; + conftemp.tempp = config.tempp*60; + measure_lcd.count=0; + measure_lcd.voltage=2305; + measure_lcd.current=1023; + measure_lcd.power=14567; + measure_lcd.energy=19876; + measure_lcd.pf=5; + measure_t433.count=0; + measure_t433.voltage=2305; + measure_t433.current=1023; + measure_t433.power=14567; + measure_t433.energy=19876; + measure_t433.pf=5; + if(config.initok != 42) { init_config(true); } + //init_config(true); + lcd.init(); // initialize the lcd + + button.setOnHold(onHoldButton, 2000); + button.setOnPress(onPressButton); + encbutton.setOnPress(onPressEncButton); + + config.state=true; + + renderer.begin(); + menu.setScreen(mainScreen); + menu_state = true; + //menu.hide(); + + //init_config(); + //save_config(); + load_config(); + if(config.pstate == true && config.state == true) { + PowerOn(); + } else if(config.pstate == false) { + config.state=false; + save_config(); + } + refresh_confdisplay(); + + lastrefreshdisp = millis(); + if(menu_state == false) { + refresh_display(); + refresh_counters(); + } + lcd.backlight(); + + transmit(); + +} + +void setup1() { + pzem.begin(); +} + +bool timer_ok(uint32_t lastmillis, uint16_t seconds) +{ + if(millis() < lastmillis) + { + return UINT16_MAX-lastmillis+millis() > seconds*1000; + Serial.println("millis reset"); + } else { + return millis() > lastmillis+seconds*1000; + } +} + +void loop() { + if(timer_ok(lastrefreshdisp, 1)) { + lastrefreshdisp = millis(); + //blink(); + refresh_display(); + } + if(conftemp.tempm_enabled) { + if(millis() % 1000 > 500) { + if(ledblinkstate == false) { ledblinkstate = true; wsled[0] = CRGB::Red; FastLED.show(); } + //Serial.println("On"); + } else { + if(ledblinkstate) { ledblinkstate = false; wsled[0] = CRGB::Black; FastLED.show(); } + //Serial.println("Off"); + } + } + if(menu_state == true) + { + menu.poll(1000); + keyboard.observe(); + } else { + button.update(); + encbutton.update(); + if(lcdsleep_state == false && timer_ok(lastbuttonactivity, config.lcdsleep)) { + lcdsleep_state = true; + lcd.noBacklight(); + lcd.noDisplay(); + } + } + if(((config.transmit_enabled == false || config.state == false) && timer_ok(lasttransmit, 30)) || (config.state == true && config.transmit_enabled == true && timer_ok(lasttransmit, config.transmitinterval))) { + lasttransmit = millis(); + transmit(); + } +} + +void add_value_measure_16(uint16_t value, uint16_t count, uint16_t *average) { + *average = *average + ((value + *average) / count); +} + +void add_value_measure_32(uint32_t value, uint16_t count, uint32_t *average) { + *average = *average + ((value + *average) / count); +} + +void loop1() { +/* + uint16_t voltage, frequency, powerFactor; + uint32_t current, power, energy; + + if(measure_kwh_reset == true) { + pzem.resetEnergy(); + measure_kwh_reset = false; + } + + if(pzem.readAllRaw(&voltage, ¤t, &power, &energy, &frequency, &powerFactor)) + { + + if(measure_t433_reset == true) { + measure_t433.count = 0; + measure_t433.voltage = 0; + measure_t433.current = 0; + measure_t433.power = 0; + measure_t433.energy = 0; + measure_t433.pf = 0; + measure_t433_reset = false; + } + + if(measure_lcd_reset == true) { + measure_lcd.count = 0; + measure_lcd.voltage = 0; + measure_lcd.current = 0; + measure_lcd.power = 0; + measure_lcd.energy = 0; + measure_lcd.pf = 0; + measure_lcd_reset = false; + } + + + measure_t433.count++; + add_value_measure_16(voltage, measure_t433.count, &(measure_t433.voltage)); + add_value_measure_32(current, measure_t433.count, &(measure_t433.current)); + add_value_measure_32(power, measure_t433.count, &(measure_t433.power)); + measure_t433.energy = energy; + add_value_measure_16(powerFactor, measure_t433.count, &(measure_t433.pf)); + + measure_lcd.count++; + add_value_measure_16(voltage, measure_lcd.count, &(measure_lcd.voltage)); + add_value_measure_32(current, measure_lcd.count, &(measure_lcd.current)); + add_value_measure_32(power, measure_lcd.count, &(measure_lcd.power)); + measure_lcd.energy = energy; + add_value_measure_16(powerFactor, measure_lcd.count, &(measure_lcd.pf)); + } +*/ + delay(1000); +}