SAJ Solar inverter

I’ve recently a new H1 in my place with a Wifi usb dongle. I’ve tried to log in with the integration with no success. I did a nmap to check which ports where open on the static ip that I’ve assigned to the device, but only ping answers. No other port is open.

In the other hand I’ve been able to use the integration thats connects to the esolar and gets the info from the cloud, but It’s not updated very often (every 5min) and I’m a bit scary that sometime in the future they break the integration and I lose all possibility to make automations based on this sensors.

Do you recommend me to change the usb dongle or, do you know if its possible to authorize by the installer to enable the ports , or is simply a feature that this device doesnt have ? Anyone has this dongle and is able to log in ?

My Inverter is an H1 and the dongle is this one. (WIFI+BLUETOOTH)

Big thanks for this one. i have been cracking my head for months on this one. It is working well for me.

1 Like

Hello. I also have a H1 with the same dongle. i spoke to SAJ and they said the dongle is the only one supported for the H1. No ip ports are open on mine as well. what i manage to see was the dongle uses MQTT to send updated to the cloud.

Hi, What @palmfields writes was also my finding. There is an article online where you can capture the mqtt traffic and do some DNS poisoning so the dongle writes data to your own mqtt server. But this is not very easy or even possible in some networks. Therefor i created the eSolar integration. If you would like you can increase the poll time you can do this in the sensor.py (overwritten after every update of the integration)

Look for:
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=5)

PS: i have choose 5 minutes to not overflood the API, as they probably do not know/approve of this integration and the API was not designed for this use. Also the dongle does not send data more frequently (so this properly is also your limit on MQTT)

1 Like

So one possible approach could be to put a MQTT server in the midde poisoning dns to capture all trafic from the inverter, and then resend this info to the real MQTT server, so in case the guys from SAJ change anything on their side, we could continue getting the info from the inverter.

In the other hand, what I really would like to have is the ability to turn on battery charge from the power company in the moment that the power is cheaper. I can only do that with the front panel or with the bluetooth app, but I cannot find a easy way to automate start / stop charging based on power price and solar estimation.

1 Like

Not knowing which mode you mostly run your inverter. I have mine always set to backup mode. I then have this Circuit Breaker between my inverter and mains.

https://www.aliexpress.com/item/4001123961363.html?spm=a2g0o.9042311.0.0.77534c4diACTr5

The Circuit Breaker provides additional protection to the inverter and also comes with eWelink. I can control when my battery starts charging from Home Assistant.

Hello,

i’m a complete newbie.
I’ve a Saj inverter + battery with a AIO3
Inverter R5-5K
Battery AS1

I’m able to collect data from the inverter but nothing from the battery. Can someone help me?

Have you alsk data from your battery?

Hi Bert,

I managed to get info from the AS1 and BS1 (they are combined when reading out data, this was recently changed by a firmware upgrade by SAJ).

My setup below (this is an extract from my sensors.yaml).

I do have to mention the pulling time is indeed 5 minutes, which is the refresh rate at which the online portal is updated. I am actually in contact with the developer team in China, to try and get this 5 min cap down, but they are not inclined to do this. I also gave the feedback that this was rediculous (they call this real-time…) and that not alot can be done with data so infrequently updated. They told me they are working on getting modbus protocols translated, but haven’t heard anything back in 6 weeks…

fingers crossed…

good luck!

- platform: saj_esolar
  username: [email protected]
  password: xxxxxx
  sensors: h1
  resources:
  - nowPower
  - runningState
  - todayElectricity
  - monthElectricity
  - yearElectricity
  - totalElectricity # Energy -> Solar production
  - lastUploadTime
  - totalPlantTreeNum
  - totalReduceCo2
  - todayAlarmNum
  - status
  - plantuid
  - currency
  - address
  - isOnline
  - devOnlineNum
  - selfUseRate
  - totalBuyElec # Energy -> Grid consumption
  - totalConsumpElec
  - totalSellElec # Energy -> Return to grid
  - pvElec
  - useElec
  - buyElec
  - sellElec
  - buyRate
  - sellRate
  - selfConsumedRate1
  - selfConsumedRate2
  - selfConsumedEnergy1
  - selfConsumedEnergy2
  - batCapcity
  - batCurr
  - batEnergyPercent
  - batteryDirection
  - batteryPower
  - gridDirection
  - gridPower
  - h1Online
  - outPower
  - outPutDirection
  - pvDirection
  - pvPower
  - solarPower
1 Like

Hey Ben,
Thanks for reply!
Where can i download the firmware update?
Can you send me the location by mail?

Hi Bert,

The firmware update was done by the SAJ team itself (I had some earlier issues with the batteries going offline because there was not enough production - I live in Belgium ergo not a lot of sun this time of the year).

I will pm you with the contact details of the chinese tech representative that handles my case.

kind regards,

Ben

Ben,

I live also in the not sunny Belgium.
Do you use the ip adres you find in the eSolar O&M app to collect the soc of your battery?

Hi Bert,

No I use the data from the online platform above (the IP’s from the communciation module of the inverter are not reachable) and the AS1 itself doesn’t have an IP.

With the configuration in my post above, you should get an entity: “sensor.esolar_batenergypercent”(amongst many other esolar entities). This entity represents the SoC of your battery.

Btw, i just received the modbus definitions for the AS1, now to test if I can get all data out of the inverter itself on a real-time frequency.

Kr,

Ben

Hi, is this still working well?

They are going to install these inverters by me, and also their 5KWh battery pack (3 of them).

Have you those too? Is somebody be able to integrate them too?

Anybody that got the latest update with what is working with the esolar AIO3?

@BenV do you have the firmware version? I want to check with my version if it’s already installed or not.
BTW I’m also one of those people that live in the not so sunny belgium :stuck_out_tongue:

Hi all,

Just to inform everyone, I managed to get the modbus protocols for the AS1 inverter (+ 1 BS module) from SAJ directly. I currently am able to pull everyting (300-400 different data sets) directly over the modbus connection (real time - 1s poll rate).

Only minor disadvantage, you have to disconnect the wifi/ethernet/bluetooth module (AIO3), in order to gain access to the RS232 port (which is an usb bus and via which the modbus communciation goes).

My (draft) setup now:

Connect usb cable to usb port on the inverter:

strip the usb cable to get only the wires connecting to the RS232 parts on the usb hub (took me a while to figure this out):

the rs232 connection scheme on the AS1 USB port:
image

connect serial RS232 to ethernet converter to pull via tcp modbus:

my home assistant modbus sensors (i only took the data i needed):

modbus:
  - name: SAJ
    close_comm_on_error: true
    delay: 5
    type: tcp
    timeout: 5
    host: 192.168.8.134
    port: 23
    sensors:
      - name: display_board_error_message
        slave: 0
        address: 16389 
        count: 2
        scale: 1
        precision: 0
        data_type: uint32
        scan_interval: 10
      - name: display_controller_error_message
        slave: 0
        address: 16391 
        count: 2
        scale: 1
        precision: 0
        data_type: uint32
        scan_interval: 10
      - name: display_controller_error_message2
        slave: 0
        address: 16393 
        count: 2
        scale: 1
        precision: 0
        data_type: uint32
        scan_interval: 10
      - name: error_message_controller
        slave: 0
        address: 16395 
        count: 2
        scale: 1
        precision: 0
        data_type: uint32
        scan_interval: 10
      - name: error_message_controller2
        slave: 0
        address: 16397 
        count: 2
        scale: 1
        precision: 0
        data_type: uint32
        scan_interval: 10 
      - name: Inverter_working_mode
        slave: 0
        address: 16388 
        count: 1
        scale: 1
        precision: 0
        data_type: uint16
        scan_interval: 1
      - name: Grid_phase_voltage
        unit_of_measurement: "V"
        slave: 0
        address: 16433 
        count: 1
        scale: 100
        precision: 0
        data_type: uint16
        device_class: voltage
        scan_interval: 1
      - name: Grid_Phase_current
        unit_of_measurement: "A"
        slave: 0
        address: 16434 
        count: 1
        precision: 2
        scale: 0
        data_type: int16
        device_class: current
        scan_interval: 1
      - name: Battery_voltage
        unit_of_measurement: "V"
        slave: 0
        address: 16489 
        count: 1
        precision: 0
        scale: 1
        data_type: uint16
        device_class: voltage
        scan_interval: 1
      - name: Battery_current
        unit_of_measurement: "A"
        slave: 0
        address: 16490 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: current
      - name: Battery_power
        unit_of_measurement: "W"
        slave: 0
        address: 16493 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Battery_temperature
        unit_of_measurement: "C°"
        slave: 0
        address: 16493 
        count: 1
        precision: 1
        scale: 1
        data_type: int16
        scan_interval: 1
        device_class: temperature
      - name: Battery_SOC
        unit_of_measurement: "%"
        slave: 0
        address: 16495 
        count: 1
        precision: 0
        scale: 0.01
        data_type: uint16
        device_class: battery
        scan_interval: 1
      - name: Battery_direction
        slave: 0
        address: 16534 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        scan_interval: 1
      - name: Gridconsumption
        unit_of_measurement: "W"
        slave: 0
        address: 16538 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: PVconsumptiontohouse
        unit_of_measurement: "W"
        slave: 0
        address: 16537 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: GridfeedinfromPV
        unit_of_measurement: "W"
        slave: 0
        address: 16539 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Gridfeedinfrombattery
        unit_of_measurement: "W"
        slave: 0
        address: 16540 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Batconsumptiontohouse
        unit_of_measurement: "W"
        slave: 0
        address: 16541 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: BatchargingfromPV
        unit_of_measurement: "W"
        slave: 0
        address: 16542 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Batchargingfromgrid
        unit_of_measurement: "W"
        slave: 0
        address: 16543 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Systemtotalloadpower
        unit_of_measurement: "W"
        slave: 0
        address: 16544 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: PVtotalpower
        unit_of_measurement: "W"
        slave: 0
        address: 16549 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Batterytotalpower
        unit_of_measurement: "W"
        slave: 0
        address: 16549 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Gridtotalpower
        unit_of_measurement: "W"
        slave: 0
        address: 16550 
        count: 1
        precision: 0
        scale: 1
        data_type: int16
        device_class: power
        scan_interval: 1
      - name: Today_pvenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16575 
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Month_pvenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16577 
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Year_pvenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16579 
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Total_pvenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16581 
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Today_batenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16583
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Month_batenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16585
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: year_batenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16587
        count: 1
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: total_batenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16589
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: totay_batdischargeenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16591
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: month_batdischargeenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16593
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: year_batdischargeenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16595
        count: 2
        precision: 0
        scale: 0.01
        data_type: int32
        device_class: energy
        scan_interval: 100
      - name: total_batdischargeenergy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16597
        count: 2
        precision: 0
        scale: 0.01
        data_type: int32
        device_class: energy
        scan_interval: 100
      - name: today_pvconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16639
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Month_pvconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16641
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Year_pvconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16643
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Total_pvconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16645
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Today_gridconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16647
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Month_gridconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16649
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: year_gridconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16651
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: total_gridconsumed_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16653
        count: 2
        precision: 0
        scale: 0.01
        data_type: int32
        device_class: energy
        scan_interval: 100
      - name: Today_gridfeedinfromPV_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16655
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Month_gridfeedinfromPV_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16657
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: year_gridfeedinfromPV_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16659
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: total_gridfeedinfromPV_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16661
        count: 2
        precision: 0
        scale: 0.01
        data_type: int32
        device_class: energy
        scan_interval: 100
      - name: Today_Totalload_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16607
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: Month_Totalload_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16609
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: year_Totalload_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16611
        count: 2
        precision: 0
        scale: 0.01
        data_type: uint32
        device_class: energy
        scan_interval: 100
      - name: total_Totalload_energy
        unit_of_measurement: "Kwh"
        slave: 0
        address: 16613
        count: 2
        precision: 0
        scale: 0.01
        data_type: int32
        device_class: energy
        scan_interval: 100

Not sure if this work on other Saj inverters, but might be worth a shot?

Probably it’s also possible to command/steer the inverter (several write-addresses were also made available) but i will not be testing this. Please PM if you would like to know more info.

kind regards,

Ben

4 Likes

Thanks for the update.
Nice to see it’s working.
I’m interested in the modbus protocols documentation.

Sadly enough I will not be able to disconnect the AIO3 module.
The app still has to work for my GF.

I’m also going to have contact with somebody of SAJ through my solar panel installer.
Going to ask what the options are.

Sorry if what I am going to say is silly, I am very new to these things… if it is a USB, couldn’t it just be split into 2 and connect the AIO3 to one of them and use the other to tinker with the RS232?

Hi George,

Not sure that will work. Typically serial communications (especially RS232) are one street-communication only, meaning that only one ‘master’ will be able to request the data. Besides using a modbus gateway, i’m not sure multiple request can be done on the serial bus of the Saj.

Not really sure as to why you would need the AOI3 module though, with this modbus pulling, you will be able to pull all information off the inverter on a real time basis (1 sec). Everything that i can think off can be pulled without having to do a lot of calculations. With this info that you pull, you can do whatever you want to visualize this in home assistant.

Updating the sofware will not work, but for that, you can decouple the modbus USB and recouple the AOI3 module if needed.

eg:

, literally allmost all of the data for this graph comes from the SaJ inverter.

good luck!

kind regards,

Ben

Hi!
I went for the dns server + mqtt proxy.
mqtt payload is binary data, sent every 10 seconds as “realtime_data”.
Does someone know about the format?
[djansen1987] mentioned some article regarding this but cannot find anything related

1 Like