Skip to content

Commit

Permalink
begin second attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
LeoDJ committed Jun 23, 2021
1 parent 1b7eae8 commit 536f96c
Show file tree
Hide file tree
Showing 11 changed files with 387 additions and 197 deletions.
Binary file added janitza-mal-umg96rm-en.pdf
Binary file not shown.
198 changes: 1 addition & 197 deletions software/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,205 +1,9 @@
#include <Arduino.h>
#include <ModbusMaster.h>
#include <Ethernet.h>

#include "globals.h"
#include "janitza.h"
#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[512];
if (len > 512) {
len = 512;
}
client.read(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);
}
}
}

void sendInfluxRequest(char *lineProtocolCommand) {
if (!client.connected()) {
if (!client.connect(INFLUX_HOST, INFLUX_PORT)) {
DEBUG.printf("Connection to InfluxDB failed\n");
return;
}
}

client.printf("POST /write?db=%s HTTP/1.1\n", INFLUX_DB);
client.printf("Host: %s\n", INFLUX_HOST);
client.printf("Authorization: Basic %s\n", INFLUX_AUTH_BASE64);
client.printf("Content-Length: %d\n", strlen(lineProtocolCommand));
client.printf("Connection: close\n");
client.printf("\n");
client.write(lineProtocolCommand);
client.printf("\n");
client.flush();
while (client.connected()) {
handleHttpResponse();
}
}

uint32_t readSerialNumber() {
uint8_t ret = mb.readHoldingRegisters(REG_SERIAL, 2);
if (ret != mb.ku8MBSuccess) {
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) {
return &registerDefinition[address - REG_DEF_START_ADDR];
}
else {
return nullptr;
}
}

#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
for (int i = 0; i < iterations; i++) {
uint16_t mbStart = startAddr + i * MB_CHUNK_SIZE;
uint8_t mbCount = MB_CHUNK_SIZE;
if (MB_CHUNK_SIZE * (i + 1) > count) {
mbCount = count % MB_CHUNK_SIZE;
}

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("\nError reading from ModBus. Status = %02X\n", ret);
return false;
}

for (int j = 0; j < mbCount; j++) {
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() {
bool success = modbusReadBulk(modbusBuf, 200, 226);

if (!success) {
DEBUG.printf("Error reading bulk from ModBus\n");
return;
}

int influxQueryLen = 0;

for (int phase = 0; phase < P_TAG_NUM; phase++) {
const char* phaseStr = phaseTagStr[phase];

influxQueryLen += sprintf(influxQueryBuf + influxQueryLen, "%s", INFLUX_MEASUREMENT); // measurement name
influxQueryLen += sprintf(influxQueryBuf + influxQueryLen, ",serial=%d,phase=%s ", _serialNumber, phaseStr); // print tags here


for (int i = 0; i < REG_DEF_NUM; i++) {
registerDefinition_t *regDef = &registerDefinition[i];

if (regDef->address == 0) { // skip "disabled" addresses
continue;
}

if (regDef->phaseTag == phase) {
int32_t mbValue = modbusBuf[i];
if (regDef->type == LONG) {
mbValue = mbValue << 16 | (modbusBuf[i + 1] & 0xFFFF);
i++; // increment counter / skip next address
}

float val = (float)mbValue / (float)regDef->multiplier;

// apply current transformer ratio if needed
if (regDef->applyCtRatio) {
val *= (float)_ctRatio;
}

influxQueryLen += sprintf(influxQueryBuf + influxQueryLen, "%s=%g,", regDef->influxStr, val);
}
}

influxQueryBuf[influxQueryLen - 1] = '\n'; // replace trailing comma with newline
}
// DEBUG.write(influxQueryBuf);
DEBUG.print("Sending InfluxDB Request... ");
sendInfluxRequest(influxQueryBuf);

}

void setup() {
DEBUG.begin(115200);
DEBUG.println("\nJanitza Power Meter to Influx\n");

MODUBS_SERIAL.begin(MODBUS_BAUD);
mb.begin(MODBUS_ADDR, MODUBS_SERIAL);

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();

readMeter();
}

uint32_t lastUpdate = 0;
void loop () {

void loop() {
if (millis() - lastUpdate >= UPDATE_INTERVAL) {
lastUpdate = millis();
readMeter();
}

handleHttpResponse();
}
10 changes: 10 additions & 0 deletions software_old/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
.vscode/settings.json

README
%AppData%
secrets.h
7 changes: 7 additions & 0 deletions software_old/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
21 changes: 21 additions & 0 deletions software_old/platformio.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:genericSTM32F103C8]
platform = [email protected]
board = bluepill_f103c8
; board = genericSTM32F103C8
framework = arduino
lib_deps =
[email protected]
[email protected]
build_flags =
-D ENABLE_HWSERIAL3
-Wl,-u_printf_float ; enable float printf
98 changes: 98 additions & 0 deletions software_old/src/eth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#include "eth.h"

uint8_t macAddr[6];
char macStr[13];
// EthernetClient net;

static inline uint64_t mix(uint64_t h) {
h ^= h >> 23;
h *= 0x2127599bf4325c37ULL;
h ^= h >> 47;
//
return h;
}

// hash function copied from https://stackoverflow.com/a/47895889
uint64_t fastHash64(const void * buf, size_t len, uint64_t seed) {
const uint64_t m = 0x880355f21e6d1965ULL;
const uint64_t * pos = (const uint64_t*)buf;
const uint64_t * end = pos + (len / 8);
const unsigned char * pos2;
uint64_t h = seed ^ (len * m);
uint64_t v;

while(pos != end)
{
v = *pos++;
h ^= mix(v);
h *= m;
}

pos2 = (const unsigned char*)pos;
v = 0;

switch(len & 7)
{
case 7: v ^= (uint64_t)pos2[6] << 48;
case 6: v ^= (uint64_t)pos2[5] << 40;
case 5: v ^= (uint64_t)pos2[4] << 32;
case 4: v ^= (uint64_t)pos2[3] << 24;
case 3: v ^= (uint64_t)pos2[2] << 16;
case 2: v ^= (uint64_t)pos2[1] << 8;
case 1: v ^= (uint64_t)pos2[0];
h ^= mix(v);
h *= m;
}

return mix(h);
}

void generateMAC(uint8_t *macArray) {

// uint32_t uid[3] = {HAL_GetUIDw0(), HAL_GetUIDw1(), HAL_GetUIDw2()};
uint64_t hash = fastHash64((uint8_t *)UID_BASE, 12, 0x421337f00beefULL);
memcpy(macArray, &hash, 6);
macArray[0] = 0x42; // set first byte to predefined value, where private bit is set

snprintf(macStr, 13, "%02X%02X%02X%02X%02X%02X", macArray[0], macArray[1], macArray[2], macArray[3], macArray[4], macArray[5]);
}

void initEthernet() {
SPI.setMOSI(SPI2_MOSI);
SPI.setMISO(SPI2_MISO);
SPI.setSCLK(SPI2_SCK);

Ethernet.init(SPI2_CS);

generateMAC(macAddr);
}

bool connectEthernet() {
DEBUG.println("Initialize Ethernet");

bool success= true;

// DHCP
if (Ethernet.begin(macAddr, 10000) == 0) {
DEBUG.println("Failed to configure Ethernet using DHCP");
success = false;
}
// Static IP
// Ethernet.begin(macAddr, IPAddress(192,168,13,245));

if (Ethernet.hardwareStatus() == EthernetNoHardware) {
DEBUG.println("Ethernet module was not found. Sorry, can't run without hardware. :(");
// delay(5000);
// HAL_NVIC_SystemReset();
} else if (Ethernet.linkStatus() == LinkOFF) {
DEBUG.println("Ethernet cable is not connected.");
success= false;
}

if(success) {
// print your local IP address:
DEBUG.print("My IP address: ");
DEBUG.println(Ethernet.localIP());
}
return success;
}
12 changes: 12 additions & 0 deletions software_old/src/eth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once
#include <SPI.h>
#include <Ethernet.h>

#include "globals.h"

extern uint8_t macAddr[6];
extern char macStr[13];
extern EthernetClient net;

void initEthernet();
bool connectEthernet();
24 changes: 24 additions & 0 deletions software_old/src/globals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#pragma once
#include <stdint.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 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
#define SPI2_SCK PB13
#define SPI2_CS PB12

#define SPI1_MOSI PA7
#define SPI1_MISO PA6
#define SPI1_SCK PA5
#define SPI1_CS PA4
File renamed without changes.
Loading

0 comments on commit 536f96c

Please sign in to comment.