mirror of https://github.com/lumapu/ahoy.git
Browse Source
# Conflicts: # tools/esp8266/app.cpp # tools/esp8266/hmInverters.h # tools/esp8266/hmSystem.h * added missing filespull/21/head
lumapu
3 years ago
11 changed files with 913 additions and 565 deletions
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
@ -0,0 +1,45 @@ |
|||
# Getting Started with an ESP8266 |
|||
|
|||
Wire Connections |
|||
|
|||
```ditaa |
|||
+-----------+ +-----------+ |
|||
| ESP8266 |--colour--| nRF24L01+ | |
|||
| | | | |
|||
| GND |---black--|[GND] | |
|||
| +3.3V |----red---| VCC | |
|||
| D4 |---grey---| CE | |
|||
| D8 |--purple--| CSN | |
|||
| D5 |---blue---| SCK | |
|||
| D7 |---green--| MOSI | |
|||
| D6 |---brown--| MISO | |
|||
| D3 |--yellow--| IRQ | |
|||
+-----------+ +-----------+ |
|||
``` |
|||
|
|||
![plot](./AhoyMiles_bb.png) |
|||
|
|||
Fritzing diagrams & schematics |
|||
* [AhoyMiles_bb.png](./AhoyMiles_bb.png) |
|||
* [AhoyMiles_schem.png](./AhoyMiles_schem.png) |
|||
* [AhoyMiles.fzz](./AhoyMiles.fzz) |
|||
|
|||
Libraries to be installed in Arduino IDE: |
|||
* RF24 |
|||
* TimeLib |
|||
|
|||
Verify & Compile |
|||
* Connect to WiFi Network `ESP AHOY` |
|||
* Use password `esp_8266` |
|||
* Connect to Network settings |
|||
|
|||
Setup |
|||
* WiFi |
|||
* Enter SSID `mynetwork` |
|||
* Enter Password `mypassword` |
|||
* Device Host Name |
|||
* Enter Device Name `esp-ahoy` |
|||
* General |
|||
* Hoymiles Address (e.g. 114173123456) `11:41:73:12:34:56` |
|||
* [x] Reboot device after successful save |
|||
Save |
File diff suppressed because it is too large
@ -0,0 +1,122 @@ |
|||
#ifndef __HM_DEFINES_H__ |
|||
#define __HM_DEFINES_H__ |
|||
|
|||
#include "debug.h" |
|||
#include <cstdint> |
|||
|
|||
// units
|
|||
enum {UNIT_V = 0, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_HZ, UNIT_C, UNIT_PCT}; |
|||
const char* const units[] = {"V", "A", "W", "Wh", "kWh", "Hz", "°C", "%"}; |
|||
|
|||
// field types
|
|||
enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, |
|||
FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT}; |
|||
const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", |
|||
"U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct"}; |
|||
|
|||
|
|||
union serial_u { |
|||
uint64_t u64; |
|||
uint8_t b[8]; |
|||
}; |
|||
|
|||
|
|||
// CH0 is default channel (freq, ac, temp)
|
|||
enum {CH0 = 0, CH1, CH2, CH3, CH4}; |
|||
// received command ids, special command CMDFF for calculations
|
|||
enum {CMD01 = 0x01, CMD02, CMD03, CMD82 = 0x82, CMD83, CMD84, CMDFF=0xff}; |
|||
|
|||
enum {INV_TYPE_HM600 = 0, INV_TYPE_HM1200, INV_TYPE_HM400}; |
|||
const char* const invTypes[] = {"HM600", "HM1200 / HM1500", "HM400"}; |
|||
#define NUM_INVERTER_TYPES 3 |
|||
|
|||
typedef struct { |
|||
uint8_t fieldId; // field id
|
|||
uint8_t unitId; // uint id
|
|||
uint8_t ch; // channel 0 - 3
|
|||
uint8_t cmdId; // received command id
|
|||
uint8_t start; // pos of first byte in buffer
|
|||
uint8_t num; // number of bytes in buffer
|
|||
uint16_t div; // divisor
|
|||
} byteAssign_t; |
|||
|
|||
|
|||
/**
|
|||
* indices are built for the buffer starting with cmd-id in first byte |
|||
* (complete payload in buffer) |
|||
* */ |
|||
|
|||
//-------------------------------------
|
|||
// HM400 HM350?, HM300?
|
|||
//-------------------------------------
|
|||
const byteAssign_t hm400assignment[] = { |
|||
{ FLD_UDC, UNIT_V, CH1, CMD01, 3, 2, 10 }, |
|||
{ FLD_IDC, UNIT_A, CH1, CMD01, 5, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH1, CMD01, 7, 2, 10 }, |
|||
{ FLD_YT, UNIT_KWH, CH1, CMD01, 9, 4, 1000 }, |
|||
{ FLD_YD, UNIT_WH, CH1, CMD01, 13, 2, 1000 }, |
|||
{ FLD_UAC, UNIT_V, CH0, CMD01, 15, 2, 10 }, |
|||
{ FLD_F, UNIT_HZ, CH0, CMD82, 1, 2, 100 }, |
|||
{ FLD_PAC, UNIT_W, CH0, CMD82, 3, 2, 10 }, |
|||
{ FLD_IAC, UNIT_A, CH0, CMD82, 7, 2, 100 }, |
|||
{ FLD_T, UNIT_C, CH0, CMD82, 11, 2, 10 } |
|||
}; |
|||
#define HM400_LIST_LEN (sizeof(hm400assignment) / sizeof(byteAssign_t)) |
|||
|
|||
|
|||
//-------------------------------------
|
|||
// HM600, HM700
|
|||
//-------------------------------------
|
|||
const byteAssign_t hm600assignment[] = { |
|||
{ FLD_UDC, UNIT_V, CH1, CMD01, 3, 2, 10 }, |
|||
{ FLD_IDC, UNIT_A, CH1, CMD01, 5, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH1, CMD01, 7, 2, 10 }, |
|||
{ FLD_UDC, UNIT_V, CH2, CMD01, 9, 2, 10 }, |
|||
{ FLD_IDC, UNIT_A, CH2, CMD01, 11, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH2, CMD01, 13, 2, 10 }, |
|||
{ FLD_YW, UNIT_WH, CH0, CMD02, 1, 2, 1 }, |
|||
{ FLD_YT, UNIT_KWH, CH0, CMD02, 3, 4, 1000 }, |
|||
{ FLD_YD, UNIT_WH, CH1, CMD02, 7, 2, 1 }, |
|||
{ FLD_YD, UNIT_WH, CH2, CMD02, 9, 2, 1 }, |
|||
{ FLD_UAC, UNIT_V, CH0, CMD02, 11, 2, 10 }, |
|||
{ FLD_F, UNIT_HZ, CH0, CMD02, 13, 2, 100 }, |
|||
{ FLD_IAC, UNIT_A, CH0, CMD02, 15, 2, 10 }, |
|||
{ FLD_T, UNIT_C, CH0, CMD83, 7, 2, 10 } |
|||
}; |
|||
#define HM600_LIST_LEN (sizeof(hm600assignment) / sizeof(byteAssign_t)) |
|||
|
|||
|
|||
//-------------------------------------
|
|||
// HM1200, HM1500
|
|||
//-------------------------------------
|
|||
const byteAssign_t hm1200assignment[] = { |
|||
{ FLD_UDC, UNIT_V, CH1, CMD01, 3, 2, 10 }, |
|||
{ FLD_IDC, UNIT_A, CH1, CMD01, 5, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH1, CMD01, 9, 2, 10 }, |
|||
{ FLD_YD, UNIT_WH, CH1, CMD02, 5, 2, 1 }, |
|||
{ FLD_YT, UNIT_KWH, CH1, CMD01, 13, 4, 1000 }, |
|||
{ FLD_UDC, UNIT_V, CH2, CMD02, 9, 2, 10 }, |
|||
{ FLD_IDC, UNIT_A, CH2, CMD01, 7, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH2, CMD01, 11, 2, 10 }, |
|||
{ FLD_YD, UNIT_WH, CH2, CMD02, 7, 2, 1 }, |
|||
{ FLD_YT, UNIT_KWH, CH2, CMD02, 1, 4, 1000 }, |
|||
{ FLD_IDC, UNIT_A, CH3, CMD02, 11, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH3, CMD02, 15, 2, 10 }, |
|||
{ FLD_YD, UNIT_WH, CH3, CMD03, 11, 2, 1 }, |
|||
{ FLD_YT, UNIT_KWH, CH3, CMD03, 3, 4, 1000 }, |
|||
{ FLD_IDC, UNIT_A, CH4, CMD02, 13, 2, 100 }, |
|||
{ FLD_PDC, UNIT_W, CH4, CMD03, 1, 2, 10 }, |
|||
{ FLD_YD, UNIT_WH, CH4, CMD03, 13, 2, 1 }, |
|||
{ FLD_YT, UNIT_KWH, CH4, CMD03, 7, 4, 1000 }, |
|||
{ FLD_UAC, UNIT_V, CH0, CMD03, 15, 2, 10 }, |
|||
{ FLD_IAC, UNIT_A, CH0, CMD84, 7, 2, 100 }, |
|||
{ FLD_PAC, UNIT_W, CH0, CMD84, 3, 2, 10 }, |
|||
{ FLD_F, UNIT_HZ, CH0, CMD84, 1, 2, 100 }, |
|||
{ FLD_PCT, UNIT_PCT, CH0, CMD84, 9, 2, 10 }, |
|||
{ FLD_T, UNIT_C, CH0, CMD84, 11, 2, 10 } |
|||
}; |
|||
#define HM1200_LIST_LEN (sizeof(hm1200assignment) / sizeof(byteAssign_t)) |
|||
|
|||
|
|||
|
|||
#endif /*__HM_DEFINES_H__*/ |
@ -0,0 +1,143 @@ |
|||
#ifndef __HM_INVERTER_H__ |
|||
#define __HM_INVERTER_H__ |
|||
|
|||
#include "hmDefines.h" |
|||
|
|||
template <class RECORDTYPE=float> |
|||
class Inverter { |
|||
public: |
|||
uint8_t id; // unique id
|
|||
char name[MAX_NAME_LENGTH]; // human readable name, eg. "HM-600.1"
|
|||
uint8_t type; // integer which refers to inverter type
|
|||
byteAssign_t* assign; // type of inverter
|
|||
uint8_t listLen; // length of assignments
|
|||
serial_u serial; // serial number as on barcode
|
|||
serial_u radioId; // id converted to modbus
|
|||
uint8_t channels; // number of PV channels (1-4)
|
|||
RECORDTYPE *record; // pointer for values
|
|||
|
|||
Inverter() { |
|||
getAssignment(); |
|||
toRadioId(); |
|||
record = new RECORDTYPE[listLen]; |
|||
memset(record, 0, sizeof(RECORDTYPE) * listLen); |
|||
} |
|||
|
|||
~Inverter() { |
|||
// TODO: cleanup
|
|||
} |
|||
|
|||
uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId) { |
|||
uint8_t pos = 0; |
|||
for(; pos < listLen; pos++) { |
|||
if((assign[pos].ch == channel) && (assign[pos].fieldId == fieldId)) |
|||
break; |
|||
} |
|||
return (pos >= listLen) ? 0xff : pos; |
|||
} |
|||
|
|||
const char *getFieldName(uint8_t pos) { |
|||
return fields[assign[pos].fieldId]; |
|||
} |
|||
|
|||
const char *getUnit(uint8_t pos) { |
|||
return units[assign[pos].unitId]; |
|||
} |
|||
|
|||
uint8_t getChannel(uint8_t pos) { |
|||
return assign[pos].ch; |
|||
} |
|||
|
|||
uint8_t getCmdId(uint8_t pos) { |
|||
return assign[pos].cmdId; |
|||
} |
|||
|
|||
void addValue(uint8_t pos, uint8_t buf[]) { |
|||
uint8_t ptr = assign[pos].start; |
|||
uint8_t end = ptr + assign[pos].num; |
|||
uint16_t div = assign[pos].div; |
|||
|
|||
uint32_t val = 0; |
|||
do { |
|||
val <<= 8; |
|||
val |= buf[ptr]; |
|||
} while(++ptr != end); |
|||
|
|||
record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div); |
|||
} |
|||
|
|||
RECORDTYPE getValue(uint8_t pos) { |
|||
return record[pos]; |
|||
} |
|||
|
|||
private: |
|||
void toRadioId(void) { |
|||
radioId.u64 = 0ULL; |
|||
radioId.b[4] = serial.b[0]; |
|||
radioId.b[3] = serial.b[1]; |
|||
radioId.b[2] = serial.b[2]; |
|||
radioId.b[1] = serial.b[3]; |
|||
radioId.b[0] = 0x01; |
|||
} |
|||
|
|||
void getAssignment(void) { |
|||
if(INV_TYPE_HM600 == type) { |
|||
listLen = (uint8_t)(HM600_LIST_LEN); |
|||
assign = (byteAssign_t*)hm600assignment; |
|||
channels = 2; |
|||
} |
|||
else if(INV_TYPE_HM1200 == type) { |
|||
listLen = (uint8_t)(HM1200_LIST_LEN); |
|||
assign = (byteAssign_t*)hm1200assignment; |
|||
channels = 4; |
|||
} |
|||
else if(INV_TYPE_HM400 == type) { |
|||
listLen = (uint8_t)(HM400_LIST_LEN); |
|||
assign = (byteAssign_t*)hm400assignment; |
|||
channels = 1; |
|||
} |
|||
else { |
|||
listLen = 0; |
|||
channels = 0; |
|||
assign = NULL; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
|
|||
/**
|
|||
* To calculate values which are not transmitted by the unit there is a generic |
|||
* list of functions which can be linked to the assignment. |
|||
* The special command 0xff (CMDFF) must be used. |
|||
*/ |
|||
|
|||
typedef float (*func_t)(Inverter<> *); |
|||
typedef struct { |
|||
uint8_t funcId; // unique id
|
|||
func_t func; // function pointer
|
|||
} calcFunc_t; |
|||
|
|||
static float calcYieldTotalCh0(Inverter<> *iv) { |
|||
if(NULL != iv) { |
|||
float yield[iv->channels]; |
|||
for(uint8_t i = 1; i <= iv->channels; i++) { |
|||
uint8_t pos = iv->getPosByChFld(i, FLD_YT); |
|||
//yield[i-1] = iv->getValue(iv)
|
|||
} |
|||
} |
|||
return 1.0; |
|||
} |
|||
|
|||
static float calcYieldDayCh0(Inverter<> *iv) { |
|||
return 1.0; |
|||
} |
|||
|
|||
enum {CALC_YT_CH0 = 0, CALC_YD_CH0}; |
|||
|
|||
const calcFunc_t calcFunctions[] = { |
|||
{ CALC_YT_CH0, &calcYieldTotalCh0 }, |
|||
{ CALC_YD_CH0, &calcYieldDayCh0 } |
|||
}; |
|||
|
|||
|
|||
#endif /*__HM_INVERTER_H__*/ |
Loading…
Reference in new issue