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