britkat1980 / giv_tcp

TCP connection (from inverter) and MQTT implementation
72 stars 32 forks source link

Unable to control AIO over MQTT #192

Open Dash opened 4 days ago

Dash commented 4 days ago

I am a new user, using 2.4.308 beta docker image. I have an AIO that is reading just fine, but when I attempt to post a control update, nothing happens.

For example, I am seeing a topic of GivEnergy/[myaio]/Control/Enable_Discharge with a value of enable. So I have attempted to toggle this by sending a raw message with MQTT Explorer to GivEnergy/control/[myaio]/enableDischarge with a value of disable. Where [myaio] is the serial for the AIO inverter.

I'm expecting to see the value then change and my battery to stop discharging, but nothing happens. I see my message published onto the MQTT queue.

I have run the container with debug logging, and this seems relevant:

Inv1 - mqtt_client -  [DEBUG   ] - MQTT Message Recieved: GivEnergy/control/[myaio]/enableDischarge= disable
Inv1 - write       -  [DEBUG   ] - Disabling Discharge
Inv1 - selector_events -  [DEBUG   ] - Using selector: EpollSelector
Inv1 - client      -  [CRITICAL] - Timeout awaiting 2:6/WriteHoldingRegisterResponse(110 -> 100/0x0064) after 11 tries at 3s, giving up
Inv1 - write       -  [ERROR   ] - Setting shallow charge 100 failed

As I haven't seen this working yet, I'm unclear as to whether this is a misconfiguration problem, or a defect.

britkat1980 commented 3 days ago

The MQTT command is correct and it is initiating a modbus command, but the inverter is not accepting it. What model and firmware is your inverter?

Dash commented 3 days ago

Invertor type is reported as: Gen1 All_in_one Firmware: D0.611-A0.611

britkat1980 commented 3 days ago

does it still happen on the latest beta release (324)

Dash commented 3 days ago

Can't get the container to start:

Jul 05 12:58:17 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:17,508 - startup - [CRITICAL] - ========================== STARTING GivTCP================================
Jul 05 12:58:17 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:17,508 - startup - [CRITICAL] - SUPERVISOR TOKEN does not exist
Jul 05 12:58:19 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:19,509 - startup - [INFO] - Searching for Inverters
Jul 05 12:58:19 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:19,509 - startup - [CRITICAL] - Scanning network for GivEnergy Devices...
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:45,907 - startup - [CRITICAL] - No inverters found...
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:45,915 - startup - [CRITICAL] - Running Redis
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  | 2024-07-05 12:58:45,916 - startup - [CRITICAL] - Running nginx
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  | Traceback (most recent call last):
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  |   File "/app/startup.py", line 398, in <module>
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  |     shutil.copyfile("settings.json",SFILE)
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  |   File "/usr/local/lib/python3.11/shutil.py", line 258, in copyfile
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  |     with open(dst, 'wb') as fdst:
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  |          ^^^^^^^^^^^^^^^
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  | FileNotFoundError: [Errno 2] No such file or directory: '/config/GivTCP/allsettings.json'
Jul 05 12:58:45 givtcp[7482]: GivTCP-1  | nginx: [emerg] cannot load certificate "/ssl/fullchain.pem": BIO_new_file() failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/ssl/fullchain.pem','r') error:2006D080:BIO routines:BIO_new_file:no such file)
Jul 05 12:58:46 givtcp[7482]: [31B blob data]
britkat1980 commented 3 days ago

That looks like you're on the Dev branch, I suggest using Beta (not Dev) as Dev is not stable, and I'm on a dev day today!

Dash commented 3 days ago

Sorry me being blind, I didn't see that one on the beta channel for some reason. No change, same original error.

[CRITICAL] - Timeout awaiting 2:6/WriteHoldingRegisterResponse(110 -> 100/0x0064) after 11 tries 
at 3s, giving up

I've tried this through a rest call too. I've also tried setChargeSlot1 through API and MQTT and while that seems to be processed, it doesn't reflect in the results or change any behaviour.

britkat1980 commented 3 days ago

How are you checking the change? The GE portal doesn't automatically update with changes from GivTCP.

Dash commented 3 days ago

Using the example payload, adjusted for correct JSON format:

{"start":"1400","finish":"1430","chargeToPercent":"55"}

I've posted it to /setChargeSlot1 and received a 200. And in the debug log, I see:

Inv1 - write       -  [DEBUG   ] - Pushing control update to mqtt: GivEnergy/CH2335G345/Control/Target_SOC - 55

Though on a more thorough read, I'm also seeing this:

Inv1 - write       -  [DEBUG   ] - Pushing control update to pkl cache: Target_SOC - 55
Inv1 - write       -  [INFO    ] - Setting Charge Target 55 was a success
Inv1 - write       -  [DEBUG   ] - Setting Charge Slot 1 to: 1200 - 1230
Inv1 - write       -  [ERROR   ] - Setting Charge Slot 1 failed

I've been trying to validate the results by monitoring the MQTT output, which shows 00:00:00 for Timeslots/Charge_start_time_slot_1 and Timeslots/Charge_end_time_slot_1; as well as Control/Charge_Target_SOC_1 still remaining at 100.

I've further attempted to validate through the Inverter information page on GE cloud by reading the register, but this also seems to confirm no change to the schedule.

Sending the above payload to MQTT on GivEnergy/control/[myaio]/setChargeSlot1 is logged as being received, but there doesn't appear to be any further action that indicates that request has been processed.

Dash commented 3 days ago

Incidentally, the docker image and what's being reported do not align on version numbers:

image image

Dash commented 1 day ago

Update on Enable Discharge. If I set this via the Cloud API, it doesn't reflect in the MQTT Control/Enable_Discharge value, which remains persistent as "enable"; although I can read it back through the cloud API. Further, it doesn't actually seem to do anything, it won't pause discharging as suggested.

I've investigated further and found that by sending a setBatteryPauseMode message to one of the enum values Disabled, PauseCharge, PauseDischarge, or PauseBoth, does indeed update the AIO and have the desired effect. It seems this has to be done in combination with a pause schedule, as if the start and end are set to 0 it has no effect. Setting 0 to 2359 works, obviously there'll be a minute at midnight when the pause is disabled again, but with the granularity available, I suspect this is the closest option. While I found the setBatteryPauseMode function in the code (undocumented), I can't see anything that lines up for setting the pause window, I'm hoping that this will be permanently written through the Cloud API and then doesn't need controlling locally.

gcoan commented 1 day ago

When setting the battery pause controls from Home Assistant I can set the start, end and mode all independently through GivTCP. Would think you should be able to do the same if calling via MQTT.

Setting the start and end time to 00:00 by the way does work for 'any time'

Dash commented 8 hours ago

I've done some more rummaging around the code base for the setChargeSlot1, which the README lists as taking the payload in https://github.com/britkat1980/giv_tcp/issues/192#issuecomment-2210845740 without any colon between hours and minutes. The REST API though does require a colon, POSTing this to /setChargeSlot1 works:

{
    "start":"14:00",
    "finish":"14:30"
}

Further reading of the code shows MQTT works quite differently: https://github.com/britkat1980/giv_tcp/blob/90f78b32060b7808a2a055cf29993219bf9d8f66/GivTCP/mqtt_client.py#L145C24-L145C39

Instead of a JSON message, it is expecting two topics being published:

Each take a raw value in the format HH:MM (e.g. 23:59). This then is shown as successful and is reflected back in the MQTT values.

I feel then this is probably just a bug report on the README more than a code bug, as a change to the code would impact anybody else who's figured this out.