diff --git a/.gitignore b/.gitignore index 54e17c93a..8beaceb68 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ tools/esp8266/binaries *.db *.suo *.ipch +tools/esp8266/.vscode/extensions.json diff --git a/tools/esp8266/app.cpp b/tools/esp8266/app.cpp index dbb3ee9ef..f70bc0517 100644 --- a/tools/esp8266/app.cpp +++ b/tools/esp8266/app.cpp @@ -81,8 +81,8 @@ void app::setup(uint32_t timeout) { if(0ULL != invSerial) { iv = mSys->addInverter(name, invSerial, modPwr); if(NULL != iv) { - DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX)); - + mEep->read(ADDR_INV_PWR_LIM + (i * 2),&iv->powerLimit); + DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit)); for(uint8_t j = 0; j < 4; j++) { mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH); } @@ -148,6 +148,7 @@ void app::setup(uint32_t timeout) { mqttPort = 1883; mMqtt.setup(mqttAddr, mqttTopic, mqttUser, mqttPwd, mqttPort); + mMqtt.mClient->setCallback(std::bind(&app::cbMqtt, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); mMqttTicker = 0; mSerialTicker = 0; @@ -229,7 +230,7 @@ void app::loop(void) { if(0 != len) { Inverter<> *iv = mSys->findInverter(&p->packet[1]); - if(NULL != iv) { + if(NULL != iv && p->packet[0] == 0x95) { uint8_t *pid = &p->packet[9]; if((*pid & 0x7F) < 5) { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], len-11); @@ -349,8 +350,15 @@ void app::loop(void) { yield(); if(mSerialDebug) DPRINTLN(DBG_INFO, F("Requesting Inverter SN ") + String(iv->serial.u64, HEX)); - mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts); - mRxTicker = 0; + if(iv->powerLimitChange){ + if(mSerialDebug) + DPRINTLN(DBG_INFO, F("Requesting Inverter to change power limit to ") + String(iv->powerLimit)); + mSys->Radio.sendControlPacket(iv->radioId.u64, uint16_t(iv->powerLimit*10)); + iv->powerLimitChange = false; + } else { + mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts); + mRxTicker = 0; + } } } else if(mSerialDebug) @@ -600,6 +608,22 @@ void app::showErase() { showReboot(); } +//----------------------------------------------------------------------------- +void app::cbMqtt(const char* topic, byte* payload, unsigned int length) { + DPRINTLN(DBG_INFO, F("app::cbMqtt")); + // DPRINTLN(DBG_INFO, topic); + // ToDo check topic ! + int inverterId = 0; // ToDo get inverter id from topic + Inverter<> *iv = this->mSys->getInverterByPos(inverterId); + if(NULL != iv) { + iv->powerLimit = std::stoi((char*)payload); + iv->powerLimitChange = true; + mEep->write(ADDR_INV_PWR_LIM + inverterId * 2,iv->powerLimit); + DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit) + F("W") ); + } +} + + //----------------------------------------------------------------------------- void app::showStatistics(void) { @@ -690,7 +714,7 @@ void app::showLiveData(void) { } modHtml += F("
" - "
") + String(iv->name) + F(""); + "
") + String(iv->name) + F(" Limit ") + String(iv->powerLimit) + F(" W"); uint8_t list[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PCT, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF}; for(uint8_t fld = 0; fld < 10; fld++) { diff --git a/tools/esp8266/app.h b/tools/esp8266/app.h index 306cb2383..96d1b9cbb 100644 --- a/tools/esp8266/app.h +++ b/tools/esp8266/app.h @@ -51,6 +51,7 @@ class app : public Main { void setup(uint32_t timeout); void loop(void); void handleIntr(void); + void cbMqtt(const char* topic, byte* payload, unsigned int length); uint8_t app_loops; uint8_t getIrqPin(void) { diff --git a/tools/esp8266/defines.h b/tools/esp8266/defines.h index c746930c8..f18dcb4c7 100644 --- a/tools/esp8266/defines.h +++ b/tools/esp8266/defines.h @@ -53,6 +53,7 @@ typedef struct { #define INV_CH_CH_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH * 4 // (4 channels) #define INV_INTERVAL_LEN 2 // uint16_t #define INV_MAX_RTRY_LEN 1 // uint8_t +#define INV_PWR_LIM_LEN MAX_NUM_INVERTERS * 2 // uint16_t #define PINOUT_LEN 3 // 3 pins: CS, CE, IRQ @@ -89,8 +90,9 @@ typedef struct { #define ADDR_INV_CH_NAME ADDR_INV_CH_PWR + INV_CH_CH_PWR_LEN #define ADDR_INV_INTERVAL ADDR_INV_CH_NAME + INV_CH_CH_NAME_LEN #define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN +#define ADDR_INV_PWR_LIM ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN -#define ADDR_MQTT_ADDR ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN +#define ADDR_MQTT_ADDR ADDR_INV_PWR_LIM + INV_PWR_LIM_LEN #define ADDR_MQTT_USER ADDR_MQTT_ADDR + MQTT_ADDR_LEN #define ADDR_MQTT_PWD ADDR_MQTT_USER + MQTT_USER_LEN #define ADDR_MQTT_TOPIC ADDR_MQTT_PWD + MQTT_PWD_LEN diff --git a/tools/esp8266/hmInverter.h b/tools/esp8266/hmInverter.h index 8a27fc883..2e65a2c7a 100644 --- a/tools/esp8266/hmInverter.h +++ b/tools/esp8266/hmInverter.h @@ -69,6 +69,8 @@ class Inverter { uint8_t type; // integer which refers to inverter type byteAssign_t* assign; // type of inverter uint8_t listLen; // length of assignments + uint16_t powerLimit; // limit power output + bool powerLimitChange; // true if change needed serial_u serial; // serial number as on barcode serial_u radioId; // id converted to modbus uint8_t channels; // number of PV channels (1-4) @@ -79,6 +81,8 @@ class Inverter { Inverter() { ts = 0; + powerLimit = -1; // 65535 W Limit -> unlimited + powerLimitChange = false; } ~Inverter() { diff --git a/tools/esp8266/hmRadio.h b/tools/esp8266/hmRadio.h index 18058e766..691001184 100644 --- a/tools/esp8266/hmRadio.h +++ b/tools/esp8266/hmRadio.h @@ -166,6 +166,28 @@ class HmRadio { return mTxChLst[mTxChIdx]; }*/ + void sendControlPacket(uint64_t invId, uint16_t data) { + DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendControlPacket")); + sendCmdPacket(invId, 0x51, 0x80, false); + mTxBuf[10] = 0x0b; // control type --> 0x0b => Type_ActivePowerContr + mTxBuf[11] = 0x00; + // 4 bytes control data + // Power Limit fix point 10 eg. 30 W --> 0d300 = 0x012c + mTxBuf[12] = (data >> 8) & 0xff; // 0x01 + mTxBuf[13] = (data ) & 0xff; // 0x2c + // + mTxBuf[14] = 0x00; + mTxBuf[15] = 0x00; + // crc control data + uint16_t crc = crc16(&mTxBuf[10], 6); + mTxBuf[16] = (crc >> 8) & 0xff; + mTxBuf[17] = (crc ) & 0xff; + // crc over all + mTxBuf[18] = crc8(mTxBuf, 18); + + sendPacket(invId, mTxBuf, 19, true); + } + void sendTimePacket(uint64_t invId, uint32_t ts) { //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendTimePacket")); sendCmdPacket(invId, 0x15, 0x80, false); diff --git a/tools/esp8266/mqtt.h b/tools/esp8266/mqtt.h index 89570344a..c6a2bf2b5 100644 --- a/tools/esp8266/mqtt.h +++ b/tools/esp8266/mqtt.h @@ -12,6 +12,8 @@ class mqtt { public: + PubSubClient *mClient; + mqtt() { mClient = new PubSubClient(mEspClient); mAddressSet = false; @@ -35,6 +37,10 @@ class mqtt { snprintf(mTopic, MQTT_TOPIC_LEN, "%s", topic); } + void setCallback(void (*func)(const char* topic, byte* payload, unsigned int length)){ + mClient->setCallback(func); + } + void sendMsg(const char *topic, const char *msg) { //DPRINTLN(DBG_VERBOSE, F("mqtt.h:sendMsg")); char top[64]; @@ -79,25 +85,25 @@ class mqtt { void loop() { //DPRINT(F("m")); - //if(!mClient->connected()) - // reconnect(); + if(!mClient->connected()) + reconnect(); mClient->loop(); } private: void reconnect(void) { - //DPRINTLN(DBG_VERBOSE, F("mqtt.h:reconnect")); + DPRINTLN(DBG_INFO, F("mqtt.h:reconnect")); if(!mClient->connected()) { if((strlen(mUser) > 0) && (strlen(mPwd) > 0)) mClient->connect(DEF_DEVICE_NAME, mUser, mPwd); else mClient->connect(DEF_DEVICE_NAME); } + mClient->subscribe("home/huette/powerset"); } WiFiClient mEspClient; - PubSubClient *mClient; - + bool mAddressSet; uint16_t mPort; char mUser[MQTT_USER_LEN]; diff --git a/tools/esp8266/platformio.ini b/tools/esp8266/platformio.ini index 0728ec479..21b37c67d 100644 --- a/tools/esp8266/platformio.ini +++ b/tools/esp8266/platformio.ini @@ -28,7 +28,6 @@ framework = arduino board = nodemcuv2 monitor_speed = 115200 board_build.f_cpu = 80000000L -upload_port = /dev/ttyUSB0 lib_deps = nrf24/RF24@1.4.2