renamed Electricity -> Power, added Energy
This commit is contained in:
parent
5790286e32
commit
f3d4c68e94
@ -7,7 +7,8 @@
|
||||
#define _ false
|
||||
|
||||
#define ____ 0
|
||||
#define HALF 127
|
||||
#define QUAR 64
|
||||
#define HALF 128
|
||||
#define FULL 255
|
||||
|
||||
#define countof(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
@ -8,7 +8,7 @@ const Color RED = {FULL, ____, ____};
|
||||
|
||||
const Color GREEN = {____, FULL, ____};
|
||||
|
||||
const Color ORANGE = {FULL, HALF, ____};
|
||||
const Color ORANGE = {FULL, QUAR, ____};
|
||||
|
||||
const Color BLUE = {____, ____, FULL};
|
||||
|
||||
|
||||
@ -99,6 +99,13 @@ bool SYMBOLS[SYMBOL_COUNT][DISPLAY_CHAR_WIDTH * DISPLAY_CHAR_HEIGHT] = {
|
||||
_, _, _,
|
||||
_, _, _,
|
||||
},
|
||||
{
|
||||
X, _, _,
|
||||
_, _, X,
|
||||
_, X, _,
|
||||
X, _, _,
|
||||
_, _, X,
|
||||
},
|
||||
// this must always be the last symbol (fallback)
|
||||
{
|
||||
X, X, X,
|
||||
|
||||
@ -5,8 +5,9 @@
|
||||
#include "Adafruit_NeoPixel.h"
|
||||
#include "Vector.h"
|
||||
|
||||
#define SYMBOL_COUNT 15
|
||||
#define SYMBOL_COUNT 16
|
||||
#define SYMBOL_DASH 13
|
||||
#define SYMBOL_PERCENT 14
|
||||
#define DISPLAY_CHAR_WIDTH 3
|
||||
#define DISPLAY_CHAR_HEIGHT 5
|
||||
|
||||
@ -94,12 +95,12 @@ public:
|
||||
LEFT, RIGHT
|
||||
};
|
||||
|
||||
uint8_t print(int x, int y, double valueDbl, Color colorPositive, Color colorZero, Color colorNegative, ALIGN align = LEFT) {
|
||||
uint8_t print2(int x, int y, double valueDbl, Color colorPositive, Color colorZero, Color colorNegative, ALIGN align = RIGHT) {
|
||||
const Color color = valueDbl == 0 ? colorZero : (valueDbl < 0 ? colorNegative : colorPositive);
|
||||
return print(x, y, valueDbl, color, align);
|
||||
return print2(x, y, valueDbl, color, align);
|
||||
}
|
||||
|
||||
uint8_t print(int x, int y, double valueDbl, Color color, ALIGN align = LEFT) {
|
||||
uint8_t print2(int x, int y, double valueDbl, Color color, ALIGN align = RIGHT) {
|
||||
if (isnan(valueDbl)) {
|
||||
x -= 3 * (DISPLAY_CHAR_WIDTH + 1) - 1;
|
||||
x += print(x, y, SYMBOL_DASH, color, true) + 1;
|
||||
@ -140,7 +141,7 @@ public:
|
||||
return DISPLAY_CHAR_WIDTH;
|
||||
}
|
||||
if (index >= SYMBOL_COUNT) {
|
||||
Serial.printf("Cannot print symbol #%u.\n", index);
|
||||
Serial.printf("Cannot print2 symbol #%u.\n", index);
|
||||
index = SYMBOL_COUNT - 1;
|
||||
}
|
||||
bool *symbolBit = SYMBOLS[index];
|
||||
|
||||
10
src/mode.cpp
10
src/mode.cpp
@ -9,7 +9,8 @@
|
||||
#include "mode/Starfield/Starfield.h"
|
||||
#include "mode/Matrix/Matrix.h"
|
||||
#include "display.h"
|
||||
#include "mode/Electricity/Electricity.h"
|
||||
#include "mode/Power/Power.h"
|
||||
#include "mode/Energy/Energy.h"
|
||||
|
||||
ModeId currentModeId = NONE;
|
||||
|
||||
@ -109,8 +110,11 @@ void loadNewMode() {
|
||||
case MATRIX:
|
||||
mode = new Matrix(display);
|
||||
break;
|
||||
case ELECTRICITY:
|
||||
mode = new Electricity(display);
|
||||
case POWER:
|
||||
mode = new Power(display);
|
||||
break;
|
||||
case ENERGY:
|
||||
mode = new Energy(display);
|
||||
break;
|
||||
default:
|
||||
Serial.print("No mode loaded.\n");
|
||||
|
||||
71
src/mode/Energy/Energy.h
Normal file
71
src/mode/Energy/Energy.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef MODE_ENERGY_H
|
||||
#define MODE_ENERGY_H
|
||||
|
||||
#include "mode/Mode.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
#define POWER_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE 287.995
|
||||
#define PV_COST_TOTAL_EURO 576.52
|
||||
#define GRID_KWH_EURO 0.33
|
||||
#define PV_COST_AMORTISATION_KWH ( PV_COST_TOTAL_EURO / GRID_KWH_EURO )
|
||||
|
||||
class Energy : public Mode {
|
||||
|
||||
private:
|
||||
|
||||
int page = 0;
|
||||
|
||||
public:
|
||||
|
||||
explicit Energy(Display &display) :
|
||||
Mode(display) {
|
||||
timer(0, 7000);
|
||||
}
|
||||
|
||||
const char *getName() override {
|
||||
return "Energy";
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void tick(uint8_t index, microseconds_t microseconds) override {
|
||||
page = (page + 1) % 3;
|
||||
}
|
||||
|
||||
void step(microseconds_t microseconds) override {
|
||||
if (realtimeChanged) {
|
||||
markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void draw(Display &display) override {
|
||||
const double produced = getPhotovoltaicEnergyKWh();
|
||||
const double imported = getGridImportKWh();
|
||||
const double exported = getGridExportKWh();
|
||||
const double producedAfterMeterChange = produced - POWER_PHOTOVOLTAIC_PRODUCED_BEFORE_METER_CHANGE;
|
||||
const double selfAfterMeterChange = producedAfterMeterChange - exported;
|
||||
const double selfRatio = selfAfterMeterChange / producedAfterMeterChange;
|
||||
const double selfConsumedKWh = selfRatio * produced;
|
||||
const double costSaved = selfConsumedKWh * GRID_KWH_EURO;
|
||||
const double amortisationPercent = selfConsumedKWh / PV_COST_AMORTISATION_KWH * 100;
|
||||
|
||||
const uint8_t l = (DISPLAY_CHAR_WIDTH + 1) * 4 - 1;
|
||||
const uint8_t r = width;
|
||||
|
||||
display.clear();
|
||||
if (page == 0) {
|
||||
display.print2(l, 0, costSaved, GREEN);
|
||||
uint8_t x = display.print2(r - DISPLAY_CHAR_WIDTH - 1, 0, amortisationPercent, WHITE);
|
||||
display.print(x, 0, SYMBOL_PERCENT, WHITE, true);
|
||||
} else if (page == 1) {
|
||||
display.print2(l, 0, getPhotovoltaicEnergyKWh(), BLUE);
|
||||
display.print2(r, 0, selfConsumedKWh, GREEN);
|
||||
} else {
|
||||
display.print2(l, 0, imported, ORANGE);
|
||||
display.print2(r, 0, exported, MAGENTA);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -23,7 +23,8 @@ enum ModeId {
|
||||
COUNT_DOWN_BARS,
|
||||
STARFIELD,
|
||||
MATRIX,
|
||||
ELECTRICITY,
|
||||
POWER,
|
||||
ENERGY,
|
||||
};
|
||||
|
||||
class Mode {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef MODE_ELECTRICITY_H
|
||||
#define MODE_ELECTRICITY_H
|
||||
#ifndef MODE_POWER_H
|
||||
#define MODE_POWER_H
|
||||
|
||||
#include "mode/Mode.h"
|
||||
#include "mqtt.h"
|
||||
@ -7,17 +7,17 @@
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "UnusedValue"
|
||||
|
||||
class Electricity : public Mode {
|
||||
class Power : public Mode {
|
||||
|
||||
public:
|
||||
|
||||
explicit Electricity(Display &display) :
|
||||
explicit Power(Display &display) :
|
||||
Mode(display) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
const char *getName() override {
|
||||
return "Electricity";
|
||||
return "Power";
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -30,8 +30,8 @@ protected:
|
||||
|
||||
void draw(Display &display) override {
|
||||
display.clear();
|
||||
display.print((DISPLAY_CHAR_WIDTH + 1) * 3 - 1, 0, getPhotovoltaicPowerW(), GREEN, Color(), Color(), Display::RIGHT);
|
||||
display.print(width, 0, getGridPowerW(), ORANGE, WHITE, MAGENTA, Display::RIGHT);
|
||||
display.print2((DISPLAY_CHAR_WIDTH + 1) * 3 - 1, 0, getPhotovoltaicPowerW(), GREEN);
|
||||
display.print2(width, 0, getGridPowerW(), ORANGE, WHITE, MAGENTA);
|
||||
}
|
||||
|
||||
};
|
||||
61
src/mqtt.cpp
61
src/mqtt.cpp
@ -8,9 +8,11 @@
|
||||
|
||||
#define MQTT_MAX_MESSAGE_AGE_MILLIS 11000
|
||||
|
||||
#define PHOTOVOLTAIC_POWER "openDTU/pv/ac/power"
|
||||
|
||||
#define GRID_POWER "electricity/grid/power/signed/w"
|
||||
#define PHOTOVOLTAIC_POWER_W "openDTU/pv/ac/power"
|
||||
#define PHOTOVOLTAIC_ENERGY_KWH "openDTU/pv/ac/yieldtotal"
|
||||
#define GRID_POWER_W "electricity/grid/power/signed/w"
|
||||
#define GRID_IMPORT_WH "electricity/grid/energy/import/wh"
|
||||
#define GRID_EXPORT_WH "electricity/grid/energy/export/wh"
|
||||
|
||||
WiFiClient espClient;
|
||||
|
||||
@ -24,10 +26,22 @@ double photovoltaicPowerW = NAN;
|
||||
|
||||
unsigned long photovoltaicPowerWLast = 0;
|
||||
|
||||
double photovoltaicEnergyKWh = NAN;
|
||||
|
||||
unsigned long photovoltaicEnergyKWhLast = 0;
|
||||
|
||||
double gridPowerW = NAN;
|
||||
|
||||
unsigned long gridPowerWLast = 0;
|
||||
|
||||
double gridImportKWh = NAN;
|
||||
|
||||
unsigned long gridImportKWhLast = 0;
|
||||
|
||||
double gridExportKWh = NAN;
|
||||
|
||||
unsigned long gridExportKWhLast = 0;
|
||||
|
||||
void mqttDisconnect();
|
||||
|
||||
void mqttCallback(char *topic, uint8_t *payload, unsigned int length) {
|
||||
@ -38,12 +52,21 @@ void mqttCallback(char *topic, uint8_t *payload, unsigned int length) {
|
||||
}
|
||||
memcpy(message, payload, length);
|
||||
message[length] = 0;
|
||||
if (strcmp(PHOTOVOLTAIC_POWER, topic) == 0) {
|
||||
if (strcmp(PHOTOVOLTAIC_POWER_W, topic) == 0) {
|
||||
photovoltaicPowerW = strtod(message, nullptr);
|
||||
photovoltaicPowerWLast = millis();
|
||||
} else if (strcmp(GRID_POWER, topic) == 0) {
|
||||
} else if (strcmp(PHOTOVOLTAIC_ENERGY_KWH, topic) == 0) {
|
||||
photovoltaicEnergyKWh = strtod(message, nullptr);
|
||||
photovoltaicEnergyKWhLast = millis();
|
||||
} else if (strcmp(GRID_POWER_W, topic) == 0) {
|
||||
gridPowerW = strtod(message, nullptr);
|
||||
gridPowerWLast = millis();
|
||||
} else if (strcmp(GRID_IMPORT_WH, topic) == 0) {
|
||||
gridImportKWh = strtod(message, nullptr) / 1000;
|
||||
gridImportKWhLast = millis();
|
||||
} else if (strcmp(GRID_EXPORT_WH, topic) == 0) {
|
||||
gridExportKWh = strtod(message, nullptr) / 1000;
|
||||
gridExportKWhLast = millis();
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,8 +82,11 @@ void mqtt_loop() {
|
||||
if (mqttConnected) {
|
||||
Serial.printf("Successfully connected mqtt broker at %s:%d\n", "10.0.0.50", 1883);
|
||||
mqtt.setCallback(mqttCallback);
|
||||
mqtt.subscribe(PHOTOVOLTAIC_POWER);
|
||||
mqtt.subscribe(GRID_POWER);
|
||||
mqtt.subscribe(PHOTOVOLTAIC_POWER_W);
|
||||
mqtt.subscribe(PHOTOVOLTAIC_ENERGY_KWH);
|
||||
mqtt.subscribe(GRID_POWER_W);
|
||||
mqtt.subscribe(GRID_IMPORT_WH);
|
||||
mqtt.subscribe(GRID_EXPORT_WH);
|
||||
} else {
|
||||
Serial.printf("ERROR: Failed to connect MQTT broker at %s:%d\n", "10.0.0.50", 1883);
|
||||
mqttDisconnect();
|
||||
@ -86,9 +112,30 @@ double getPhotovoltaicPowerW() {
|
||||
return photovoltaicPowerW;
|
||||
}
|
||||
|
||||
double getPhotovoltaicEnergyKWh() {
|
||||
if (millis() - photovoltaicEnergyKWhLast > MQTT_MAX_MESSAGE_AGE_MILLIS) {
|
||||
return NAN;
|
||||
}
|
||||
return photovoltaicEnergyKWh;
|
||||
}
|
||||
|
||||
double getGridPowerW() {
|
||||
if (millis() - gridPowerWLast > MQTT_MAX_MESSAGE_AGE_MILLIS) {
|
||||
return NAN;
|
||||
}
|
||||
return gridPowerW;
|
||||
}
|
||||
|
||||
double getGridImportKWh() {
|
||||
if (millis() - gridImportKWhLast > MQTT_MAX_MESSAGE_AGE_MILLIS) {
|
||||
return NAN;
|
||||
}
|
||||
return gridImportKWh;
|
||||
}
|
||||
|
||||
double getGridExportKWh() {
|
||||
if (millis() - gridExportKWhLast > MQTT_MAX_MESSAGE_AGE_MILLIS) {
|
||||
return NAN;
|
||||
}
|
||||
return gridExportKWh;
|
||||
}
|
||||
|
||||
@ -5,6 +5,12 @@ void mqtt_loop();
|
||||
|
||||
double getPhotovoltaicPowerW();
|
||||
|
||||
double getPhotovoltaicEnergyKWh();
|
||||
|
||||
double getGridPowerW();
|
||||
|
||||
double getGridImportKWh();
|
||||
|
||||
double getGridExportKWh();
|
||||
|
||||
#endif
|
||||
|
||||
@ -105,7 +105,8 @@ void web_index() {
|
||||
server.sendContent(R"(<a onclick="get('/mode?mode=10');">COUNT_DOWN_BARS</a><br>)");
|
||||
server.sendContent(R"(<a onclick="get('/mode?mode=11');">STARFIELD</a><br>)");
|
||||
server.sendContent(R"(<a onclick="get('/mode?mode=12');">MATRIX</a><br>)");
|
||||
server.sendContent(R"(<a onclick="get('/mode?mode=13');">ELECTRICITY</a><br>)");
|
||||
server.sendContent(R"(<a onclick="get('/mode?mode=13');">POWER</a><br>)");
|
||||
server.sendContent(R"(<a onclick="get('/mode?mode=14');">ENERGY</a><br>)");
|
||||
server.sendContent(R"(</p>)");
|
||||
|
||||
server.sendContent(R"(<p>)");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user