Browse Source

Merge remote-tracking branch 'upstream/development03' into development03

pull/772/head
Daniel Michalik 2 years ago
parent
commit
2781604e23
  1. 4
      Getting_Started.md
  2. 2
      README.md
  3. 10
      User_Manual.md
  4. 2
      src/defines.h
  5. 38
      src/hm/miPayload.h
  6. 4
      src/plugins/Display/Display.h
  7. 18
      tools/rpi/README.md
  8. 42
      tools/rpi/ahoy_system.service

4
Getting_Started.md

@ -53,6 +53,10 @@ Hoymiles Inverters
- HM1000?
- HM1200
- HM1500
- MI-300* [For MI inverters see remarks here](User_Manual.md#mi-inverters)
- MI-600*
- MI-700*
- MI-1500* (2nd gen. still untested)
TSUN Inverters:

2
README.md

@ -48,4 +48,4 @@ Please try to describe your issues as precise as possible and think about if thi
- [OpenDTU](https://github.com/tbnobody/OpenDTU)
<- Our sister project for Hoymiles HM-300, HM-600, HM-1200 (for ESP32 only!)
- [DTU Simulator](https://github.com/Ziyatoe/DTUsimMI1x00-Hoymiles)
<- Go here for Hoymiles MI-300, MI-600, MI-1200 Software
<- Go here for Hoymiles MI-300, MI-600, MI-1200 Software (single inverter only)

10
User_Manual.md

@ -285,6 +285,8 @@ To get the information open the URL `/api/record/info` on your AhoyDTU. The info
| tomquist | TSOL-M1600 | | 1.0.12 | 2020 | 06-24 | 100 | | |
| rejoe2 | MI-600 | | 236 | 2018 | 11-27 | 17 | | |
| rejoe2 | MI-1500 | | 1.0.12 | 2020 | 06-24 | 100 | | |
| dragricola | HM-1200 | | 1.0.16 | 2021 | 10-12 | 100 | | |
| dragricola | MI-300 | | 230 | 2017 | 08-08 | 1 | | |
| | | | | | | | | |
## Developer Information about Command Queue
@ -319,3 +321,11 @@ Send Power Limit:
- A persistent limit is only needed if you want to throttle your inverter permanently or you can use it to set a start value on the battery, which is then always the switch-on limit when switching on, otherwise it would ramp up to 100% without regulation, which is continuous load is not healthy.
- You can set a new limit in the turn-off state, which is then used for on (switching on again), otherwise the last limit from before the turn-off is used, but of course this only applies if DC voltage is applied the whole time.
- If the DC voltage is missing for a few seconds, the microcontroller in the inverter goes off and forgets everything that was temporary/non-persistent in the RAM: YieldDay, error memory, non-persistent limit.
## Additional Notes
### MI Inverters
- AhoyDTU supports MI type inverters as well, since dev. version 0.5.70.
- MI inverters are known to be delivered with two different generations of firmwares: inverters with serial numbers 10x2 already use the 3rd generation protocol and behave just like the newer HM models, *the follwoing remarks do not apply to these*.
- Older MI inverters (#sn 10x1) use a different rf protocol and thus do not deliver exactly the same data. E.g. the AC power value will therefore be calculated by AhoyDTU itself, while other values might not be available at all.
- Single and dual channel 2nd gen. devices seem not to accept power limiting commands at all, the lower limit for 4-channel MI is 10% (instead of 2% for newer models)
- 4-channel MI type inverters might work, but code still is untested.

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 5
#define VERSION_PATCH 100
#define VERSION_PATCH 101
//-------------------------------------
typedef struct {

38
src/hm/miPayload.h

@ -118,7 +118,7 @@ class MiPayload {
//DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX));
if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09
miStsDecode(iv, p);
miStsDecode(iv, p), CH1;
}
else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11
@ -361,6 +361,7 @@ const byteAssign_t InfoAssignment[] = {
if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) {
cmd = 0x11;
change = true;
mPayload[iv->id].retransmits = 0; //reset counter
}
}
} else if ( cmd == 0x11) {
@ -468,15 +469,16 @@ const byteAssign_t InfoAssignment[] = {
(mCbMiPayload)(val);
}
void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t chan = CH1) {
void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) {
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX));
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure
rec->ts = mPayload[iv->id].ts;
mPayload[iv->id].gotFragment = true;
mPayload[iv->id].txId = p->packet[0];
uint8_t status = (p->packet[11] << 8) + p->packet[12];
uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2;
//uint8_t status = (p->packet[11] << 8) + p->packet[12];
uint8_t status = (p->packet[9] << 8) + p->packet[10];
//uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2;
mPayload[iv->id].sts[stschan] = status;
mPayload[iv->id].stsAB[stschan] = true;
if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2])
@ -495,20 +497,6 @@ const byteAssign_t InfoAssignment[] = {
//mPayload[iv->id].skipfirstrepeat = 1;
if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) {
miComplete(iv);
/*mPayload[iv->id].complete = true;
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs"));
iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0));
//preliminary AC calculation...
uint8_t ac_pow = 0;
//if (mPayload[iv->id].sts[0] == 3) {
ac_pow = calcPowerDcCh0(iv, 0)*9.5;
//}
iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10));
iv->setQueuedCmdFinished();
iv->doCalculations();
mPayload[iv->id].skipfirstrepeat = 0;
notify(mPayload[iv->id].txCmd);
yield();*/
}
}
@ -632,10 +620,16 @@ const byteAssign_t InfoAssignment[] = {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0));
//preliminary AC calculation...
uint8_t ac_pow = 0;
//if (mPayload[iv->id].sts[0] == 3) {
ac_pow = calcPowerDcCh0(iv, 0)*9.5;
//}
for(uint8_t i = 1; i <= iv->channels; i++) {
if (mPayload[iv->id].sts[i] == 3) {
uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec);
ac_pow += iv->getValue(pos, rec);
}
}
ac_pow = ac_pow*9.5;
iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10));
iv->doCalculations();
iv->setQueuedCmdFinished();
@ -693,7 +687,7 @@ const byteAssign_t InfoAssignment[] = {
mPayload[id].skipfirstrepeat = 0;
mPayload[id].requested = false;
mPayload[id].ts = *mTimestamp;
mPayload[id].sts[0] = 0; //disable this in case gotFragment is not working
mPayload[id].sts[0] = 0;
mPayload[id].sts[CH1] = 0;
mPayload[id].sts[CH2] = 0;
mPayload[id].sts[CH3] = 0;

4
src/plugins/Display/Display.h

@ -25,7 +25,7 @@ class Display {
if (mCfg->type == 0)
return;
if ((1 < mCfg->type) && (mCfg->type < 10)) {
if ((0 < mCfg->type) && (mCfg->type < 10)) {
mMono.config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast);
mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion);
} else if (mCfg->type >= 10) {
@ -79,7 +79,7 @@ class Display {
totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec);
}
if ((1 < mCfg->type) && (mCfg->type < 10)) {
if ((0 < mCfg->type) && (mCfg->type < 10)) {
mMono.disp(totalPower, totalYieldDay, totalYieldTotal, isprod);
} else if (mCfg->type >= 10) {
#if defined(ESP32)

18
tools/rpi/README.md

@ -21,14 +21,22 @@ Required Hardware Setup
`ahoy.py` has been successfully tested with the following setup
- RaspberryPi Model 2B (any model should work)
- RaspberryPi Model 2B, 4B (any model should work)
- NRF24L01+ Radio Module connected as described, e.g., in [2]
(Instructions at [3] should work identically, but [2] has more
pretty pictures.)
- or the [PaHoy board](https://github.com/DM6JM/PaHoy/)
- TMRh20's 'Optimized High Speed nRF24L01+ Driver' [3], installed
as per the instructions given in [4]
- Python Library Wrapper, as per [5]
- or the easy way, using [pyRF24](https://github.com/nRF24/pyRF24)[6]
How to talk to the nRF24L01+ in Python?
---------------------------------------
Either you make use of the way proposed in the following, using the NRF24 Python Wrapper and the 'Optimized High Speed nRF24L01+ Driver' OR you just use pip and let it install pyRF24.
- If you go with pyRF24, all that needs to be done is installing pyRF24 as described in [6]. Please be aware that not all examples provided in this repo are prepared to use pyRF24. It might be nescessary to adjust the imports from RF24 to pyRF24 to get them running. Once you installed pyRF24, go on at 'Required python modules'
- If you go with the RF24 wrapper, do the following steps
Building the NRF24 Python Wrapper
---------------------------------
@ -220,7 +228,12 @@ Example injects exactly the same as we normally use to poll data
This allows for even faster hacking during runtime
Running it as a service
-----------------------
If you want to run directly from the start, you might want to install it as a service.
Depending on if you want to run it once a user is logged in or as soon as the system is booted, two service examples are included.
ahoy.service allows you to start it as a user service upon login.
ahoy_system.service allows you to start it as a system service already before login without user interaction.
Analysing the Logs
------------------
@ -263,3 +276,4 @@ References
- [3] https://nrf24.github.io/RF24/index.html
- [4] https://nrf24.github.io/RF24/md_docs_linux_install.html
- [5] https://nrf24.github.io/RF24/md_docs_python_wrapper.html
- [6] https://github.com/nRF24/pyRF24

42
tools/rpi/ahoy_system.service

@ -0,0 +1,42 @@
######################################################################
# systemd.service configuration for ahoy (lumapu)
# users can modify the lines:
# Description
# ExecStart (example: name of config file)
# WorkingDirectory (absolute path to your private ahoy dir)
# To change other config parameter, please consult systemd documentation
#
# To activate this service, enable and start ahoy.service:
# - Create folder ahoy in /home/ and set owner to the user that the
# service should be executed for (e.g. pi)
# - Copy folder contents to new folder
# - Adjust the user that this service should be executed as, avoid root
# - Execute commands to setup, check and start/stop as wanted
# $ sudo systemctl enable /home/ahoy/tools/rpi/ahoy.service
# $ sudo systemctl status ahoy
# $ sudo systemctl start ahoy
# $ sudo systemctl stop ahoy
#
# 2023.01 <PaeserBastelstube>
# 2023.03 <DM6JM>
######################################################################
[Unit]
Description=ahoy (lumapu) as Service
After=network.target local-fs.target time-sync.target
[Service]
ExecStart=/usr/bin/env python3 -um hoymiles --log-transactions --verbose --config ahoy.yml
RestartSec=10
Restart=on-failure
Type=simple
User=pi
# WorkingDirectory must be an absolute path - not relative path
WorkingDirectory=/home/ahoy/tools/rpi
EnvironmentFile=/etc/environment
[Install]
WantedBy=default.target
Loading…
Cancel
Save