diff --git a/software/.gitignore b/software/.gitignore index 5666c5d..1713e29 100644 --- a/software/.gitignore +++ b/software/.gitignore @@ -3,6 +3,7 @@ .vscode/c_cpp_properties.json .vscode/launch.json .vscode/ipch +.vscode/settings.json README %AppData% diff --git a/software/src/globals.h b/software/src/globals.h index bd655aa..8efd73a 100644 --- a/software/src/globals.h +++ b/software/src/globals.h @@ -1,18 +1,17 @@ #pragma once #include -#include "secrets.h" +#include "secrets.h" // don't forget to create secrets.h based on the .sample file #define DEBUG Serial1 #define UPDATE_INTERVAL 5000 // ms -#define CT_RATIO (40/5) // calculated current transformer ratio (e.g. 40:5 -> 8) #define MODUBS_SERIAL Serial3 #define MODBUS_BAUD 38400 #define MODBUS_ADDR 1 - +// put InfluxDB credentials into secrets.h #define SPI2_MOSI PB15 #define SPI2_MISO PB14 diff --git a/software/src/janitza.h b/software/src/janitza.h index 64cf96c..a33d634 100644 --- a/software/src/janitza.h +++ b/software/src/janitza.h @@ -85,16 +85,16 @@ const char *phaseTagStr[] = { - - - +#define REG_SERIAL 911 +#define REG_CT_PRIM 600 +#define REG_CT_SEC 601 #define EMPTY {0, 1, false, INT, P_ALL, NULL} #define LONG_SPACER EMPTY - // TODO: fix addresses (currently not needed) +// array is aligned with line numbers for easier referencing registerDefinition_t registerDefinition[] = { //addr multipl CTratio type phase name { 200, 10, false, INT, P_L1, "U_LN" }, @@ -142,30 +142,30 @@ registerDefinition_t registerDefinition[] = { { 1, 10, false, INT, P_L3, "U_LN_Harm11" }, { 1, 10, false, INT, P_L3, "U_LN_Harm13" }, { 1, 10, false, INT, P_L3, "U_LN_Harm15" }, - { 1, 1, false, INT, P_L1, "I_Harm1" }, - { 1, 1, false, INT, P_L1, "I_Harm3" }, - { 1, 1, false, INT, P_L1, "I_Harm5" }, - { 1, 1, false, INT, P_L1, "I_Harm7" }, - { 1, 1, false, INT, P_L1, "I_Harm9" }, - { 1, 1, false, INT, P_L1, "I_Harm11" }, - { 1, 1, false, INT, P_L1, "I_Harm13" }, - { 1, 1, false, INT, P_L1, "I_Harm15" }, - { 1, 1, false, INT, P_L2, "I_Harm1" }, - { 1, 1, false, INT, P_L2, "I_Harm3" }, - { 1, 1, false, INT, P_L2, "I_Harm5" }, - { 1, 1, false, INT, P_L2, "I_Harm7" }, - { 1, 1, false, INT, P_L2, "I_Harm9" }, - { 1, 1, false, INT, P_L2, "I_Harm11" }, - { 1, 1, false, INT, P_L2, "I_Harm13" }, - { 1, 1, false, INT, P_L2, "I_Harm15" }, - { 1, 1, false, INT, P_L3, "I_Harm1" }, - { 1, 1, false, INT, P_L3, "I_Harm3" }, - { 1, 1, false, INT, P_L3, "I_Harm5" }, - { 1, 1, false, INT, P_L3, "I_Harm7" }, - { 1, 1, false, INT, P_L3, "I_Harm9" }, - { 1, 1, false, INT, P_L3, "I_Harm11" }, - { 1, 1, false, INT, P_L3, "I_Harm13" }, - { 1, 1, false, INT, P_L3, "I_Harm15" }, + { 1, 1, true, INT, P_L1, "I_Harm1" }, + { 1, 1, true, INT, P_L1, "I_Harm3" }, + { 1, 1, true, INT, P_L1, "I_Harm5" }, + { 1, 1, true, INT, P_L1, "I_Harm7" }, + { 1, 1, true, INT, P_L1, "I_Harm9" }, + { 1, 1, true, INT, P_L1, "I_Harm11" }, + { 1, 1, true, INT, P_L1, "I_Harm13" }, + { 1, 1, true, INT, P_L1, "I_Harm15" }, + { 1, 1, true, INT, P_L2, "I_Harm1" }, + { 1, 1, true, INT, P_L2, "I_Harm3" }, + { 1, 1, true, INT, P_L2, "I_Harm5" }, + { 1, 1, true, INT, P_L2, "I_Harm7" }, + { 1, 1, true, INT, P_L2, "I_Harm9" }, + { 1, 1, true, INT, P_L2, "I_Harm11" }, + { 1, 1, true, INT, P_L2, "I_Harm13" }, + { 1, 1, true, INT, P_L2, "I_Harm15" }, + { 1, 1, true, INT, P_L3, "I_Harm1" }, + { 1, 1, true, INT, P_L3, "I_Harm3" }, + { 1, 1, true, INT, P_L3, "I_Harm5" }, + { 1, 1, true, INT, P_L3, "I_Harm7" }, + { 1, 1, true, INT, P_L3, "I_Harm9" }, + { 1, 1, true, INT, P_L3, "I_Harm11" }, + { 1, 1, true, INT, P_L3, "I_Harm13" }, + { 1, 1, true, INT, P_L3, "I_Harm15" }, { 1, 10, false, INT, P_L1, "THD_U" }, { 1, 10, false, INT, P_L2, "THD_U" }, { 1, 10, false, INT, P_L3, "THD_U" }, @@ -176,9 +176,9 @@ registerDefinition_t registerDefinition[] = { { 1, 100, false, INT, P_ALL, "CosPhi" }, { 1, 1, false, INT, P_ALL, "Rotation" }, { 1, 1, false, INT, P_ALL, "I_N" }, - { 1, 1, false, INT, P_ALL, "P" }, - { 1, 1, false, INT, P_ALL, "Q" }, - { 1, 1, false, INT, P_ALL, "S" }, + { 1, 1, true, INT, P_ALL, "P" }, + { 1, 1, true, INT, P_ALL, "Q" }, + { 1, 1, true, INT, P_ALL, "S" }, EMPTY, // { 0, 1, true, INT, P_L1, "I_Mean" }, EMPTY, // { 0, 1, true, INT, P_L2, "I_Mean" }, EMPTY, // { 0, 1, true, INT, P_L3, "I_Mean" }, @@ -313,19 +313,16 @@ registerDefinition_t registerDefinition[] = { EMPTY, EMPTY, EMPTY, - { 1, 1, false, LONG, P_ALL, "Wp" }, // Wh + { 1, 1, true, LONG, P_ALL, "Wp" }, // Wh LONG_SPACER, - { 1, 1, false, LONG, P_ALL, "Wq" }, + { 1, 1, true, LONG, P_ALL, "Wq" }, LONG_SPACER, EMPTY, EMPTY, - { 1, 1, false, LONG, P_ALL, "Wp_Import" }, // Wh + { 1, 1, true, LONG, P_ALL, "Wp_Import" }, // Wh LONG_SPACER, - { 1, 1, false, LONG, P_ALL, "Wp_Supply" }, // Wh + { 1, 1, true, LONG, P_ALL, "Wp_Supply" }, // Wh LONG_SPACER, }; #define REG_DEF_NUM (sizeof(registerDefinition) / sizeof(registerDefinition[0])) -#define REG_DEF_START_ADDR 200 - - -#define REG_SERIAL 911 \ No newline at end of file +#define REG_DEF_START_ADDR 200 \ No newline at end of file diff --git a/software/src/main.cpp b/software/src/main.cpp index 8f4aa4a..7db3146 100644 --- a/software/src/main.cpp +++ b/software/src/main.cpp @@ -7,22 +7,29 @@ #include "eth.h" - ModbusMaster mb; uint32_t _serialNumber; +uint16_t _ctRatio = 1; EthernetClient client; + void handleHttpResponse() { // print response from HTTP request if (client.available()) { int len = client.available(); - uint8_t buf[256]; - if (len > 256) { - len = 256; + uint8_t buf[512]; + if (len > 512) { + len = 512; } client.read(buf, len); - DEBUG.write(buf, len); + if (strncmp((const char *)buf, "HTTP/1.1 204", 12) == 0) { + DEBUG.println("InfluxDB request successful."); + } + else { + DEBUG.println("InfluxDB request failed!"); + DEBUG.write(buf, len); + } } } @@ -51,12 +58,22 @@ void sendInfluxRequest(char *lineProtocolCommand) { uint32_t readSerialNumber() { uint8_t ret = mb.readHoldingRegisters(REG_SERIAL, 2); if (ret != mb.ku8MBSuccess) { - DEBUG.printf("Error reading from ModBus. Status = %02X\n", ret); + DEBUG.printf("Error reading from ModBus in readSerialNumber. Status = %02X\n", ret); return 0; } return mb.getResponseBuffer(0) << 16 | mb.getResponseBuffer(1); } +uint16_t readCtRatio() { + uint8_t ret = mb.readHoldingRegisters(REG_CT_PRIM, 2); + if (ret != mb.ku8MBSuccess) { + DEBUG.printf("Error reading from ModBus in readCtRatio. Status = %02X\n", ret); + return 0; + } + // calculate CT ratio, only integers supported currently + return mb.getResponseBuffer(0) / mb.getResponseBuffer(1); +} + registerDefinition_t *getRegDef(uint16_t address) { // currently the definition is still continuous, so we don't actually have to search through it if (address >= REG_DEF_START_ADDR && address <= REG_DEF_START_ADDR + REG_DEF_NUM) { @@ -67,7 +84,7 @@ registerDefinition_t *getRegDef(uint16_t address) { } } -#define MB_CHUNK_SIZE 64 +#define MB_CHUNK_SIZE 32 bool modbusReadBulk(int16_t *destBuf, uint16_t startAddr, uint16_t count) { int iterations = (count + (MB_CHUNK_SIZE - 1)) / MB_CHUNK_SIZE; // division, but rounded up @@ -78,12 +95,12 @@ bool modbusReadBulk(int16_t *destBuf, uint16_t startAddr, uint16_t count) { mbCount = count % MB_CHUNK_SIZE; } - DEBUG.printf("Reading Modbus Addr: %d, Count: %d\n", mbStart, mbCount); + DEBUG.printf("Reading Modbus %d/%d (Addr: %d, Count: %d) \r", i+1, iterations, mbStart, mbCount); uint8_t ret = mb.readHoldingRegisters(mbStart, mbCount); if (ret != mb.ku8MBSuccess) { - DEBUG.printf("Error reading from ModBus. Status = %02X\n", ret); + DEBUG.printf("\nError reading from ModBus. Status = %02X\n", ret); return false; } @@ -91,14 +108,15 @@ bool modbusReadBulk(int16_t *destBuf, uint16_t startAddr, uint16_t count) { destBuf[i * MB_CHUNK_SIZE + j] = mb.getResponseBuffer(j); } } + DEBUG.printf("\n"); return true; } int16_t modbusBuf[REG_DEF_NUM]; +char influxQueryBuf[512*10]; void readMeter() { - // readMeterChunk(200, 64); bool success = modbusReadBulk(modbusBuf, 200, 226); if (!success) { @@ -106,12 +124,11 @@ void readMeter() { return; } - char influxQueryBuf[512]; + int influxQueryLen = 0; for (int phase = 0; phase < P_TAG_NUM; phase++) { const char* phaseStr = phaseTagStr[phase]; - int influxQueryLen = 0; influxQueryLen += sprintf(influxQueryBuf + influxQueryLen, "%s", INFLUX_MEASUREMENT); // measurement name influxQueryLen += sprintf(influxQueryBuf + influxQueryLen, ",serial=%d,phase=%s ", _serialNumber, phaseStr); // print tags here @@ -134,21 +151,18 @@ void readMeter() { // apply current transformer ratio if needed if (regDef->applyCtRatio) { - val *= (float)CT_RATIO; + val *= (float)_ctRatio; } influxQueryLen += sprintf(influxQueryBuf + influxQueryLen, "%s=%g,", regDef->influxStr, val); } } - influxQueryBuf[influxQueryLen - 1] = 0; // clear trailing comma - - DEBUG.write(influxQueryBuf); - DEBUG.println(); - - sendInfluxRequest(influxQueryBuf); - handleHttpResponse(); + influxQueryBuf[influxQueryLen - 1] = '\n'; // replace trailing comma with newline } + // DEBUG.write(influxQueryBuf); + DEBUG.print("Sending InfluxDB Request... "); + sendInfluxRequest(influxQueryBuf); } @@ -159,9 +173,19 @@ void setup() { MODUBS_SERIAL.begin(MODBUS_BAUD); mb.begin(MODBUS_ADDR, MODUBS_SERIAL); - _serialNumber = readSerialNumber(); - DEBUG.printf("Serial: %d\n", _serialNumber); - // readMeter(); + while (_serialNumber == 0) { + _serialNumber = readSerialNumber(); + if (_serialNumber != 0) { + DEBUG.printf("Serial: %d\n", _serialNumber); + } + else { + DEBUG.printf("Error: Could not read serial number, make sure the meter is connected and address and baud rate are correct. Retrying in 5s...\n"); + delay(5000); + } + } + + _ctRatio = readCtRatio(); + DEBUG.printf("CT Ratio: %d\n", _ctRatio); initEthernet(); connectEthernet(); @@ -177,4 +201,5 @@ void loop() { readMeter(); } + handleHttpResponse(); } \ No newline at end of file