First commit

This commit is contained in:
Nigreon 2025-12-30 22:41:30 +01:00
commit 22df5b1e33
2 changed files with 664 additions and 0 deletions

16
platformio.ini Normal file
View File

@ -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

648
src/lcdcrystal.ino Normal file
View File

@ -0,0 +1,648 @@
#include <LiquidCrystal_I2C.h>
#include <SimpleRotary.h>
#include <EEPROM.h>
#include <FastLED.h>
#include <msToString.h>
#include <RH_ASK.h>
#include <RHEncryptedDriver.h>
#include <Speck.h>
#include <AES.h>
#include <TcBUTTON.h>
#include <PZEM004T.h>
#include <ItemBool.h>
#include <ItemList.h>
#include <ItemRange.h>
#include <ItemCommand.h>
#include <ItemSubMenu.h>
#include <LcdMenu.h>
#include <MenuScreen.h>
#include <display/LiquidCrystal_I2CAdapter.h>
#include <input/KeyboardAdapter.h>
#include <renderer/CharacterDisplayRenderer.h>
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<bool> value) { config.pstate = value; save_config(); }, "%s"),
ITEM_BOOL_REF("T433", config.transmit_enabled, "Oui", "Non", [](const Ref<bool> value) { config.transmit_enabled = value; save_config(); }, "%s"),
ITEM_BOOL_REF("Watt-", config.wattm_enabled, "Oui", "Non", [](const Ref<bool> value) { config.wattm_enabled = value; save_config(); }, "%s"),
ITEM_BOOL_REF("Watt+", config.wattp_enabled, "Oui", "Non", [](const Ref<bool> value) { config.wattp_enabled = value; save_config(); }, "%s"),
ITEM_BOOL_REF("Tempo avant(-)", conftemp.tempm_enabled, "Oui", "Non", [](const Ref<bool> 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<bool> value) { conftemp.tempp_enabled = value; conftemp.tempp = config.tempp*60; }, "%s"));
MENU_SCREEN(settingsScreen, settingsItems,
ITEM_RANGE_REF<uint16_t>("Watt-", config.wattm, 1, 10, 3670, [](const Ref<uint16_t> value) { config.wattm = value; save_config(); }, "%04dW"),
ITEM_RANGE_REF<uint16_t>("Watt+", config.wattp, 1, 20, 3680, [](const Ref<uint16_t> value) { config.wattp = value; save_config(); }, "%04dW"),
ITEM_WIDGET(
"Ecran(mm:ss)",
[](const Ref<uint16_t> minute, const Ref<uint16_t> second) { config.lcdsleep = minute*60+second; save_config(); },
WIDGET_RANGE_REF<uint16_t>(lcdsleep.minute, 1, 0, 59, "%02d", 0, false),
WIDGET_RANGE_REF<uint16_t>(lcdsleep.second, 1, 0, 59, ":%02d", 0, false)),
ITEM_WIDGET(
"T433(mm:ss)",
[](const Ref<uint16_t> minute, const Ref<uint16_t> second) { config.transmitinterval = minute*60+second; save_config(); },
WIDGET_RANGE_REF<uint16_t>(transmitinterval.minute, 1, 0, 4, "%02d", 0, false),
WIDGET_RANGE_REF<uint16_t>(transmitinterval.second, 1, 0, 59, ":%02d", 0, false)),
ITEM_WIDGET(
"Temp-(hh:mm)",
[](const Ref<uint16_t> hour, const Ref<uint16_t> minute) { config.tempm = hour*60+minute; save_config(); },
WIDGET_RANGE_REF<uint16_t>(tempm.hour, 1, 0, 23, "%02d", 0, false),
WIDGET_RANGE_REF<uint16_t>(tempm.minute, 1, 0, 59, ":%02d", 0, false)),
ITEM_WIDGET(
"Temp+(hh:mm)",
[](const Ref<uint16_t> hour, const Ref<uint16_t> minute) { config.tempp = hour*60+minute; save_config(); },
WIDGET_RANGE_REF<uint16_t>(tempp.hour, 1, 0, 23, "%02d", 0, false),
WIDGET_RANGE_REF<uint16_t>(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<maxchar-strlen(valuestr);i++) {
ret[i]=' ';
}
}
ret[maxchar-strlen(valuestr)]='\0';
strcat(ret, valuestr);
strcat(ret, unit.c_str());
return ret;
}
void refresh_values() {
char retval[15];
//Serial.println(create_value(measure_lcd.voltage, retval, "V", 1, 5));
create_value(measure_lcd.voltage+counter*10, retval, "V", 1, 1, 5);
lcd.setCursor(2, 0);
lcd.print(retval);
create_value(measure_lcd.current, retval, "A", 2, 2, 5);
lcd.setCursor(11, 0);
lcd.print(retval);
create_value(measure_lcd.power, retval, "W", 0, 1, 4);
lcd.setCursor(0, 1);
lcd.print(retval);
create_value(measure_lcd.pf, retval, "%", 0, 0, 3);
lcd.setCursor(7, 1);
lcd.print(retval);
create_value(measure_lcd.energy, retval, "kWh", 1, 3, 5);
lcd.setCursor(12, 1);
lcd.print(retval);
measure_lcd_reset = true;
}
void refresh_temp()
{
if(conftemp.tempp_enabled == true && config.state == true) {
lcd.setCursor(3, 3);
lcd.print('+');
lcd.setCursor(4, 3);
lcd.print(msToString(conftemp.tempp*1000, S, sizeof(S), true, true, true, 2));
}
if(conftemp.tempm_enabled == true && config.state == false) {
lcd.setCursor(3, 3);
lcd.print('-');
lcd.setCursor(4, 3);
lcd.print(msToString(conftemp.tempm*1000, S, sizeof(S), true, true, true, 2));
}
}
void refresh_counters()
{
if(config.state) {
config.counter_all++;
}
lcd.setCursor(1, 2);
lcd.print(msToString(config.counter_all*1000, S, sizeof(S), true, true, true, 2));
lcd.setCursor(11, 2);
lcd.print(msToString(config.counter_used*1000, S, sizeof(S), true, true, true, 2));
}
void refresh_display()
{
//Serial.print("HelloWorld!!! ");
//Serial.print(msToString(counter*1000, S, sizeof(S), true, true, true, 2));
counter++;
//Serial.print(" ");
//Serial.println(millis());
//lcd.setCursor(3,0);
//lcd.print("Hello, world!");
if(conftemp.tempm_enabled == true && config.state == false) {
if(conftemp.tempm > 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<WS2812, 16, GRB>(wsled, 1);
EEPROM.begin(256);
delay(500);
if (!driver.init()) { Serial.println("RHinit 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, &current, &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);
}