Sessy home battery script

Python and python framework

Moderator: leecollings

Post Reply
Mike70
Posts: 21
Joined: Thursday 22 October 2015 19:46
Target OS: Raspberry Pi / ODroid
Domoticz version: bèta
Location: Netherlands
Contact:

Sessy home battery script

Post by Mike70 »

I made a script to use with the Sessy home battery.
It reads the percentage, current power, update status and 3 different device states of the home battery and P1 meter dongle.
It calculates the total amount of delivered and stored kWh.

You can also follow the Tweakers forum.

For this script you have to use the following python3 libraries: requests, numpy, urllib3
Install them with:
sudo pip3 install requests
sudo pip3 install numpy
sudo pip3 install urllib3

Create Hardware
1: Type 'Dummy (Does nothing,use for virtual switches only)' and call it 'Sessy Home battery'

Create up to 20 sensors for each Sessy.
1: Sensor type 'Percentage' and call it 'Sessy battery percentage'
2: Sensor type 'Usage (Electric)' and call it 'Sessy battery power'
3: Sensor type 'Electric (Instant+Counter)' and call it 'Sessy Battery Energy Delivered' Go to Utility select the device and set 'type' to 'Return' and 'Energy read' to Computed
4: Sensor type 'Electric (Instant+Counter)' and call it 'Sessy Battery Energy Stored' Go to Utility select the device and set 'type' to 'Usage' and set 'Energy read' to Computed
5: Sensor type 'Text' and call it 'Sessy battery state'
6: Sensor type 'Text' and call it 'Sessy battery detailed state'
7: Sensor type 'Custom Sensor' and call it 'Mains frequency'
8: Sensor type 'Voltage' and call it 'Mains phase 1 voltage'
9: Sensor type 'Ampere (1 Phase)'and call it 'Mains phase 1 Current'
10: Sensor type 'Usage (Electric)' and call it 'Mains phase 1 power'
11: Sensor type 'Voltage' and call it 'Mains phase 2 voltage'
12: Sensor type 'Ampere (1 Phase)'and call it 'Mains phase 2 Current'
13: Sensor type 'Usage (Electric)' and call it 'Mains phase 2 power'
14: Sensor type 'Voltage' and call it 'Mains phase 3 voltage'
15: Sensor type 'Ampere (1 Phase)'and call it 'Mains phase 3 Current'
16: Sensor type 'Usage (Electric)' and call it 'Mains phase 3 power'
17: Sensor type 'Text' and call it 'Sessy P1 meter state'
18: Sensor type 'Text' and call it 'Sessy battery update state'
19: Sensor type 'Text' and call it 'Sessy serial update state'
20: Sensor type 'Text' and call it 'P1 meter update state'

If you use more than one sessy, you can also add these two sensors.
1: Sensor type 'Percentage' and call it 'Sessy average battery percentage'
2: Sensor type 'Usage (Electric)' and call it 'Sessy average battery power'

Note the IDX of the devices and put them in the script.
You also need the 'Web UI', Password and IP-addresses of the Sessy Home battery and Sessy P1 Meter.
If you use Epaper, then you also need the 'Epaper access point' address.

If you want to run the script with crontab?
Add the next line to crontab.
* * * * * ~/domoticz/scripts/python/sessy/sessy.py

The program creates a PID file to prevent multiple instances of the program from running.

You can set the read interval of the battery and the P1 meter yourself.

Please feel free to add your own sensors and do not hestitate to ask your questions or problems here...

11-06-2023 V1.1.0: Made a few changes.
Added 15 more sensors.
Domoticz calculates the total amount of stored and delivered kWh.
The update status of the devices are shown.
Added 2 phases for a 3 phase mains system used.


12-12-2023 V1.5.0: Made a few changes.
You can now use more than 1 battery in this script.
If you use Debug = True, you can see if the data send to Domoticz is accepted or not.


05-02-2024 V2.0.0: Made a few changes.
Added a watchdog if the Url commands not respond anymore.
Added ability to use a 2.9" Epaper to see the current state of the battery.
The Epaper update is every 10 minutes.
See: https://www.tindie.com/stores/electronics-by-nic/
Image

Save the code as domoticz/scripts/python/sessy.py

Code: Select all

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-

# Python Program to read data from 1 or more sessy home batteries.
# Author: Minke Bergsma
# Version: 2.0.0

# The program creates a PID file to prevent multiple instances of the program from running.
# If you use 'Debug = True', you will see a green 'V' at the beginning of the line if Domoticz has accepted the sent data.
# Otherwise, you will see a red 'X' and you need to check your variables or a white '-' when the IDX = -1.

# To use it with Domoticz:

# Create Hardware
#  1: Type 'Dummy (Does nothing,use for virtual switches only)' and call it 'Sessy Home battery'

# Create these virtual sensors for each sessy battery
#  1: Sensor type 'Percentage' and call it 'Sessy battery percentage'
#  2: Sensor type 'Usage (Electric)' and call it 'Sessy battery power'
#  3: Sensor type 'Electric (Instant+Counter)' and call it 'Sessy Battery Energy Delivered' Go to Utility select the device and set 'type' to 'Return' and 'Energy read' to Computed
#  4: Sensor type 'Electric (Instant+Counter)' and call it 'Sessy Battery Energy Stored' Go to Utility select the device and set 'type' to 'Usage' and set 'Energy read' to Computed
#  5: Sensor type 'Text' and call it 'Sessy battery state'
#  6: Sensor type 'Text' and call it 'Sessy battery detailed state'
#  7: Sensor type 'Custom Sensor' and call it 'Mains frequency'
#  8: Sensor type 'Voltage' and call it 'Mains phase 1 voltage'
#  9: Sensor type 'Ampere (1 Phase)'and call it 'Mains phase 1 Current'
# 10: Sensor type 'Usage (Electric)' and call it 'Mains phase 1 power'
# 11: Sensor type 'Voltage' and call it 'Mains phase 2 voltage'
# 12: Sensor type 'Ampere (1 Phase)'and call it 'Mains phase 2 Current'
# 13: Sensor type 'Usage (Electric)' and call it 'Mains phase 2 power'
# 14: Sensor type 'Voltage' and call it 'Mains phase 3 voltage'
# 15: Sensor type 'Ampere (1 Phase)'and call it 'Mains phase 3 Current'
# 16: Sensor type 'Usage (Electric)' and call it 'Mains phase 3 power'
# 17: Sensor type 'Text' and call it 'Sessy P1 meter state'
# 18: Sensor type 'Text' and call it 'Sessy battery update state'
# 19: Sensor type 'Text' and call it 'Sessy serial update state'
# 20: Sensor type 'Text' and call it 'P1 meter update state'

# If you use more than one sessy, you can also add these two sensors.
#  1: Sensor type 'Percentage' and call it 'Average battery percentage'
#  2: Sensor type 'Usage (Electric)' and call it 'Average battery power'

# Note the idx numbers of the of the devices and use them in the section 'devices IDX in Domoticz'.

# Running with crontab?
# Add the next line to crontab.
# * * * * * ~/domoticz/scripts/python/sessy/sessy.py

import json
import os
import time
import datetime
import requests
import urllib.request
import numpy as sessy
from threading import Timer

from PIL import Image, ImageDraw, ImageFont

########################################################################
# Settings to be changed.
#

Debug = False
WatchdogTimeOut = 0.5 # Time in seconds before an Url call is timed out. If you get to many Watchdog timeouts, please set te timeout higher.

# Hostadresses and login data for Sessy P1 Meter and Sessy WiFi serial.
#

# Url Domoticz
DomoticzHost = 'xxx.xxx.xxx.xxx:pppp' # IP address and port number

# devices IDX in Domoticz (-1 is not used.)

# Array for singele battery
# BatteryArray = sessy.array([[BatteryPercentageIDX, BatteryPowerIDX, BatteryEnergyDeliveredIDX, BatteryEnergyStoredIDX, BatterySystemStateIDX, BatterySystemStateDetailsIDX, BatteryUpdateIDX, BatterySerialUpdateIDX]])

# Array for 2 or more batteries
# BatteryArray = sessy.array([[Battery1IPaddress, Battery1Username, Battery1Password, Battery1PercentageIDX, Battery1PowerIDX, Battery1EnergyDeliveredIDX, Battery1EnergyStoredIDX, Battery1SystemStateIDX, Battery1SystemStateDetailsIDX, Battery1UpdateIDX, Battery1SerialUpdateIDX],
#                             [Battery2IPaddress, Battery2Username, Battery2Password, Battery2PercentageIDX, Battery2PowerIDX, Battery2EnergyDeliveredIDX, Battery2EnergyStoredIDX, Battery2SystemStateIDX, Battery2SystemStateDetailsIDX, Battery2UpdateIDX, Battery2SerialUpdateIDX]])
BatteryArray = sessy.array([["xxx.xxx.xxx.xxx", "AAAAAAAA", "BBBBBBBB", -1, -1, -1, -1, -1, -1, -1, -1],
                            ["yyy.yyy.yyy.yyy", "CCCCCCCC", "DDDDDDDD", -1, -1, -1, -1, -1, -1, -1, -1]])

# Mains array. You should only use the data from the mains from the battery where your inverter is connected to.
# MainsArray = sessy.array([MainsFrequencyIDX, MainsPhase1VoltageIDX, MainsPhase1CurrentIDX, MainsPhase1PowerIDX, MainsPhase2VoltageIDX, MainsPhase2CurrentIDX, MainsPhase2PowerIDX, MainsPhase3VoltageIDX, MainsPhase3CurrentIDX, MainsPhase3PowerIDX])
MainsArray = sessy.array([-1, -1, -1, -1, -1, -1, -1, -1, -1 ,-1])

# P1 meter array
# P1Array = sessy.array([[P1Host, P1Username, P1Password, P1MeterStatusIDX, P1MeterUpdateIDX]])
P1Array = sessy.array(["zzz.zzz.zzz.zzz", "EEEEEEEE", "FFFFFFFF", -1, -1])

# The average battery percentage and power IDX in Domoticz.
AveragePercentageIDX = -1
AveragePowerIDX = -1

# Interval times to read the Battery data and the P1 meter data.
NumberOfBatteries = len(BatteryArray)
ReadInterval = 2

# If you want to use Epaper, set the variable UseEpaper to true.
# https://www.tindie.com/stores/electronics-by-nic/
# https://github.com/jjwbruijn/OpenEPaperLink
UseEpaper = False
EpaperApIp = "xxx.xxx.xxx.ddxxxd" # ip address of your Epaper access point
# Array for a single EPaper.
# EPaperArray = sessy.array(['Battery name', 'MMMMMMMMMMMMMMMM']) # MMMMMMMMMMMMMMMM = Mac address of the Epaper. (16 characters)

# Array for 2 or more EPapers
# EPaperArray = sessy.array([['Battery name 1', 'MMMMMMMMMMMMMMMM'],  # MMMMMMMMMMMMMMMM = Mac address of the Epaper. (16 characters)
#                            ['Battery name 2', 'NNNNNNNNNNNNNNNN']]) # NNNNNNNNNNNNNNNN = Mac address of the Epaper. (16 characters)
                           
########################################################################

########################################################################
# Do not change anything beneath this point.
# Url combinations
SecundairyReadInterval = (ReadInterval * 10)
P1MeterReadInterval = (ReadInterval * 30)
UrlSessyP1 = 'http://'+ P1Array[1] + ':' + P1Array[2] + '@' + P1Array[0]

script_name = os.path.basename(__file__)
pidfile = os.path.join("/tmp", os.path.splitext(script_name)[0]) + ".pid"

def create_pidfile():
    if os.path.exists(pidfile):
        with open(pidfile, "r") as _file:
            last_pid = int(_file.read())

        # Checking if process is still running
        last_process_cmdline = "/proc/%d/cmdline" % last_pid
        if os.path.exists(last_process_cmdline):
            with open(last_process_cmdline, "r") as _file:
                cmdline = _file.read()
            if script_name in cmdline:
                raise Exception("Script already running...")

    with open(pidfile, "w") as _file:
        pid = str(os.getpid())
        _file.write(pid)

def GetDataFromDevice(Url):
    try:
       watchdog = Watchdog(WatchdogTimeOut)
       response = requests.get(Url)
       jsonData = json.loads(response.text)
       watchdog.stop()       
       return jsonData
    except Watchdog:
        watchdog.stop()

def SendDataToDomoticz(IDX, Data, Show200 = True):
    try:
        watchdog = Watchdog(WatchdogTimeOut)
        if int(IDX) >= 0:
            url = 'http://' + DomoticzHost + "/json.htm?type=command&param=udevice&idx=" + str(IDX) + "&svalue=" + Data
            r = requests.get(url)
            watchdog.stop()
            if Show200:
                if '[200]' in str(r):
                    PrintToScreen(f'\033[A\r\x1b[1;32mV\x1b[0m')
                else:
                    PrintToScreen(f'\033[A\r\x1b[1;31mX\x1b[0m')           
    except Watchdog:
        watchdog.stop()
        PrintToScreen(f'\033[A\r\x1b[1;33mT\x1b[0m')

def PrintToScreen (Data):
    if Debug == True:
        print(Data)

def UpdateEpaper (Mac, SessyName, Percentage, Status, Power):
    FillColorStatus = 1
    FillColorPercentage = 1
    FillColorCharching = 2
    dither = 0   # set dither to 1 is you're sending photos etc
    Charching = 'Ontladen'
    
    if Percentage < 11:
        FillColorPercentage = 2

    if Power < 0:
        Charching = 'Opladen'
        FillColorCharching = 1
    #    Power = Power * -1

    if Status == 'kritieke fout':
        FillColorStatus = 2

    # Create a new paletted image with indexed colors
    image = Image.new('P', (296, 128))

    # Define the color palette (white, black, red)
    palette = [
        255, 255, 255,  # white
        0, 0, 0,        # black
        255, 0, 0       # red
    ]

    # Assign the color palette to the image
    image.putpalette(palette)

    # Initialize the drawing context
    draw = ImageDraw.Draw(image)

    # Define the fonts and sizes
    font_Text = ImageFont.truetype('/home/minke/domoticz/scripts/python/sessy/arial.ttf', size=21)

    # Write the text on the image
    draw.multiline_text((80,  10), SessyName, fill=1, font=font_Text, anchor=None, spacing=10, align='right')    
    draw.multiline_text((80,  35), 'Status: ' + Status, fill=FillColorStatus, font=font_Text, anchor=None, spacing=10, align='right')
    draw.multiline_text((80, 100), 'Lading: ' + str(Percentage) + '%', fill=FillColorPercentage, font=font_Text, anchor=None, spacing=10, align='right')

    if Power != 0:
        font_Text = ImageFont.truetype('/home/minke/domoticz/scripts/python/sessy/arial.ttf', size=42)
        draw.multiline_text((80, 56), Charching, fill=FillColorCharching, font=font_Text, anchor=None, spacing=10, align='right')    

    # Draw Battery
    draw.rectangle([ 4, 15, 70, 123], fill=None, outline=1, width=7)
    draw.rectangle([24,  4, 51,  18], fill=None, outline=1, width=4)

    if Percentage != 0:
        Ystart = int(111 - ((84 / 100) * Percentage))
        draw.rectangle([16, Ystart, 58, 111], fill=FillColorPercentage, outline=FillColorPercentage, width=1)
        
    # Convert the image to 24-bit RGB
    rgb_image = image.convert('RGB')

    # Save the image as JPEG with maximum quality
    image_path = '/home/minke/domoticz/scripts/python/sessy/' + Mac + '.jpg'
    rgb_image.save(image_path, 'JPEG', quality="maximum")

    # Prepare the HTTP POST request
    url = "http://" + EpaperApIp + "/imgupload"
    payload = {"dither": dither, "mac": Mac}  # Additional POST parameter
    files = {"file": open(image_path, "rb")}  # File to be uploaded

    # Send the HTTP POST request
    try:
        watchdog = Watchdog(WatchdogTimeOut)
        response = requests.post(url, data=payload, files=files)
        watchdog.stop()
        # Check the response status
        if response.status_code == 200:
            PrintToScreen(f'\033[A\r\x1b[1;32mV\x1b[0m')
        else:
            PrintToScreen(f'\033[A\r\x1b[1;31mX\x1b[0m')
    except Watchdog:
        watchdog.stop()
        PrintToScreen(f'\033[A\r\x1b[1;33mT\x1b[0m')

def main():
    OldSecond = -1
    while True:
        time.sleep(0.1)
        Second = time.localtime().tm_sec
        Minute = time.localtime().tm_min
        if (Second %ReadInterval == 0 or Second %SecundairyReadInterval == 0 or Second %P1MeterReadInterval == 0) and OldSecond != Second:
            # Set variables
            number = 0
            AveragePercentage = 0
            AveragePower = 0
            OldSecond = Second

            # Clear the screen
            PrintToScreen('\033c')

            # Get the requested data from the sessy battery
            # /api/v1/network/status
            # /api/v1/ota/check
            # /api/v1/ota/start
            # /api/v1/ota/status
            # /api/v1/power/setpoint
            # /api/v1/power/status
            # /api/v1/power/active_strategy
            # /api/v1/system/settings
            # /api/v1/system/info

            # Get the requested data from the sessy P1 meter
            # /api/v1/network/status
            # /api/v1/ota/check
            # /api/v1/ota/start
            # /api/v1/ota/status
            # /api/v1/p1/status
            # /api/v1/system/info

            PrintToScreen("   Minute                  = " + str(Minute))
            PrintToScreen("   Second                  = " + str(Second))
            PrintToScreen("")

# Secundairy data
            PrintToScreen("   Number of batteries     = " + str(NumberOfBatteries))

            while number <= NumberOfBatteries - 1:
                UrlBattery = 'http://'+ BatteryArray[number, 1] + ':' + BatteryArray[number, 2] + '@' + BatteryArray[number, 0]
                if Second %ReadInterval == 0:
                    PrintToScreen("")
                    RecievedDataBattery = GetDataFromDevice(UrlBattery + '/api/v1/power/status')
                    StatusDataBattery = RecievedDataBattery['status']
                    PrintToScreen("   Data status battery " + str(number + 1) + "   = " + StatusDataBattery)

                    if StatusDataBattery == 'ok':
                        # Get the battery percentage and send it to Domoticz
                        if int(BatteryArray[number,3]) > -1:
                            BatteryPercentage = str(round(RecievedDataBattery['sessy']['state_of_charge'] * 100))
                            AveragePercentage += int(BatteryPercentage)
                            PrintToScreen("   Battery percentage      = " + BatteryPercentage + " %")
                            SendDataToDomoticz (BatteryArray[number,3], BatteryPercentage)

                        # Get the battery power and send it to Domoticz
                        if int(BatteryArray[number,4]) > -1:
                            BatteryPower = str(RecievedDataBattery['sessy']['power'])
                            AveragePower += int(BatteryPower)
                            PrintToScreen("   Battery power           = " + BatteryPower + " W.")
                            SendDataToDomoticz (BatteryArray[number,4], BatteryPower)

                        if int(BatteryPower) > 0:
                            if int(BatteryArray[number,5]) > -1:
                                SendDataToDomoticz (BatteryArray[number,5], BatteryPower, False)
                            if int(BatteryArray[number,6]) > -1:
                                SendDataToDomoticz (BatteryArray[number,6], "0", False)
                        else:
                            if int(BatteryArray[number,6]) > -1:
                                SendDataToDomoticz (BatteryArray[number,6], str(int(BatteryPower) * - 1), False)
                            if int(BatteryArray[number,5]) > -1:
                                SendDataToDomoticz (BatteryArray[number,5], "0", False)

# Secundairy data
                        if Second %SecundairyReadInterval == 0:
                            # Get the battery state and send it to Domoticz
                            if int(BatteryArray[number,7]) > -1:
                                BatteryState = str(RecievedDataBattery['sessy']['system_state'])
                                PrintToScreen("   Battery system state    = " + BatteryState)
                                SendDataToDomoticz (BatteryArray[number,7], BatteryState)

                            # Get the battery detailed state and send it to Domoticz
                            if int(BatteryArray[number,8]) > -1:
                                BatteryStateDetails = str(RecievedDataBattery['sessy']['system_state_details'])
                                if BatteryStateDetails == "":
                                    BatteryStateDetails = "All systems functioning within normal parameters"

                            PrintToScreen("   Battery detail state    = " + BatteryStateDetails)
                            SendDataToDomoticz (BatteryArray[number,8], BatteryStateDetails)

                            if number == 0:
                                # Get the mains frequency and send it to Domoticz
                                if int(MainsArray[0]) > -1:
                                    BatteryFrequency = str(RecievedDataBattery['sessy']['frequency'] / 1000)
                                    PrintToScreen("   Mains frequency         = " + BatteryFrequency + " Hz.")
                                    SendDataToDomoticz (MainsArray[0], BatteryFrequency)

                                # Get the mains phase 1 voltage
                                if int(MainsArray[1]) > -1:
                                    MainsPhase1Voltage = str(RecievedDataBattery['renewable_energy_phase1']['voltage_rms'] / 1000)
                                    PrintToScreen("   Mains phase 1 voltage   = " + MainsPhase1Voltage + " V.")
                                    SendDataToDomoticz (MainsArray[1], MainsPhase1Voltage)

                                # Get the mains phase 1 current
                                if int(MainsArray[2]) > -1:
                                    MainsPhase1Current = str(RecievedDataBattery['renewable_energy_phase1']['current_rms'] / 1000)
                                    PrintToScreen("   Mains phase 1 current   = " + MainsPhase1Current + " A.")
                                    SendDataToDomoticz (MainsArray[2], MainsPhase1Current)

                                # Get the mains phase 1 power
                                if int(MainsArray[3]) > -1:
                                    MainsPhase1Power = str(RecievedDataBattery['renewable_energy_phase1']['power'])
                                    PrintToScreen("   Mains phase 1 power     = " + MainsPhase1Power + " W.")
                                    SendDataToDomoticz (MainsArray[3], MainsPhase1Power)

                                # Get the mains phase 2 voltage
                                if int(MainsArray[4]) > -1:
                                    MainsPhase2Voltage = str(RecievedDataBattery['renewable_energy_phase2']['voltage_rms'] / 2000)
                                    PrintToScreen("   Mains phase 2 voltage   = " + MainsPhase2Voltage + " V.")
                                    SendDataToDomoticz (MainsArray[4], MainsPhase2Voltage)

                                # Get the mains phase 2 current
                                if int(MainsArray[5]) > -1:
                                    MainsPhase2Current = str(RecievedDataBattery['renewable_energy_phase2']['current_rms'] / 2000)
                                    PrintToScreen("   Mains phase 2 current   = " + MainsPhase2Current + " A.")
                                    SendDataToDomoticz (MainsArray[5], MainsPhase2Current)

                                # Get the mains phase 2 power
                                if int(MainsArray[6]) > -1:
                                    MainsPhase2Power = str(RecievedDataBattery['renewable_energy_phase2']['power'])
                                    PrintToScreen("   Mains phase 2 power     = " + MainsPhase2Power + " W.")
                                    SendDataToDomoticz (MainsArray[6], MainsPhase2Power)

                                # Get the mains phase 3 voltage
                                if int(MainsArray[7]) > -1:
                                    MainsPhase3Voltage = str(RecievedDataBattery['renewable_energy_phase3']['voltage_rms'] / 3000)
                                    PrintToScreen("   Mains phase 3 voltage   = " + MainsPhase3Voltage + " V.")
                                    SendDataToDomoticz (MainsArray[7], MainsPhase3Voltage)

                                # Get the mains phase 3 current
                                if int(MainsArray[8]) > -1:
                                    MainsPhase3Current = str(RecievedDataBattery['renewable_energy_phase3']['current_rms'] / 3000)
                                    PrintToScreen("   Mains phase 3 current   = " + MainsPhase3Current + " A.")
                                    SendDataToDomoticz (MainsArray[8], MainsPhase3Current)

                                # Get the mains phase 3 power
                                if int(MainsArray[9]) > -1:
                                    MainsPhase3Power = str(RecievedDataBattery['renewable_energy_phase3']['power'])
                                    PrintToScreen("   Mains phase 3 power     = " + MainsPhase3Power + " W.")
                                    SendDataToDomoticz (MainsArray[9], MainsPhase3Power)

 # Update status
                        if Minute == 0 and Second == 0:
                            PrintToScreen("   Battery " + str(number + 1) + " update check  = " + str(GetDataFromDevice(UrlBattery + '/api/v1/ota/check')['status']))

                        if  Minute == 0 and Second == 30:
                            RecievedBatteryUpdate = GetDataFromDevice(UrlBattery + '/api/v1/ota/status')
                            StatusBatteryUpdate = RecievedDataBattery['status']
                            PrintToScreen("   Update status battery " + str(number + 1) + " = " + StatusBatteryUpdate)

                            if StatusBatteryUpdate == 'ok':
                                if int(BatteryArray[number,9]) > -1:
                                    BatteryUpdate = str(RecievedBatteryUpdate['self']['state'])
                                    BatteryUpdate = BatteryUpdate + " (V "+ str(RecievedBatteryUpdate['self']['available_firmware']['version'] + ")")
                                    PrintToScreen("   Battery update status   = " + BatteryUpdate)
                                    SendDataToDomoticz (int(BatteryArray[number,9]), BatteryUpdate)

                                if int(BatteryArray[number,10]) > -1:
                                    SerialUpdate = str(RecievedBatteryUpdate['serial']['state'])
                                    SerialUpdate = SerialUpdate + " (V "+ str(RecievedBatteryUpdate['serial']['available_firmware']['version'] + ")")
                                    PrintToScreen("   Serial update status    = " + SerialUpdate)
                                    SendDataToDomoticz (int(BatteryArray[number,10]), SerialUpdate)

                    if (Second == 0 and Minute %5 == 0) and UseEpaper == True and EPaperArray[number, 1] != '0':
                        # Send data to Epaper.
                        if BatteryState == 'SYSTEM_STATE_BATTERY_EMPTY':
                            BatteryState = 'batterij leeg'
                        elif BatteryState == 'SYSTEM_STATE_BATTERY_FULL':
                            BatteryState = 'batterij vol'
                        elif BatteryState == 'SYSTEM_STATE_RUNNING_SAFE':
                            BatteryState = 'aktief'
                        elif BatteryState == 'SYSTEM_STATE_STANDBY' or BatteryState == 'SYSTEM_STATE_INIT' or BatteryState == 'SYSTEM_STATE_WAIT_FOR_PERIPHERALS' or BatteryState == 'SYSTEM_STATE_DISCONNECT' or BatteryState == 'SYSTEM_STATE_RECONNECT':
                            BatteryState = 'standby'
                        elif BatteryState == 'SYSTEM_STATE_WAITING_FOR_SAFE_SITUATION':
                            BatteryState = 'wacht op net'
                        elif BatteryState == 'SYSTEM_STATE_WAITING_IN_SAFE_SITUATION':
                            BatteryState = 'aktiveren'
                        elif BatteryState == 'SYSTEM_STATE_OVERRIDE_OVERFREQUENCY' or BatteryState == 'SYSTEM_STATE_OVERRIDE_UNDERFREQUENCY':
                            BatteryState = 'freq. stabil.'
                        else:
                            BatteryState = 'kritieke fout'
                            
                        PrintToScreen('   Update EPaper data')
                        UpdateEpaper (str(EPaperArray[number,1]), str(EPaperArray[number,0]), int(BatteryPercentage), BatteryState, int(BatteryPower))
                        
                    number +=1

# P1 meter data
            if Second %P1MeterReadInterval == 0:
                PrintToScreen("")
                RecievedDataP1Meter = GetDataFromDevice(UrlSessyP1 + '/api/v1/p1/status')
                StatusDataP1Meter = RecievedDataP1Meter['status']
                PrintToScreen("   Data status P1 meter    = " + StatusDataP1Meter)
                if int(P1Array[3]) > -1:
                    SessyP1MeterStatus = str(RecievedDataP1Meter['state'])
                    PrintToScreen("   P1 meter state          = " + SessyP1MeterStatus)
                    SendDataToDomoticz (P1Array[3], SessyP1MeterStatus)

            if Minute == 0 and Second == 0:
                PrintToScreen("   P1 meter update check   = " + str(GetDataFromDevice(UrlSessyP1 + '/api/v1/ota/check')['status']))

            if Minute == 0 and Second == 30:
                RecievedP1Update = GetDataFromDevice(UrlSessyP1 + '/api/v1/ota/status')
                StatusP1Update = RecievedDataBattery['status']
                PrintToScreen("")
                PrintToScreen("   Update status P1 meter  = " + StatusP1Update)
                if StatusP1Update == 'ok':
                    if int(P1Array[4]) > -1:
                        P1MeterUpdate = str(RecievedP1Update['self']['state'])
                        P1MeterUpdate = P1MeterUpdate + " (V "+ str(RecievedP1Update['self']['available_firmware']['version'] + ")")
                        PrintToScreen("   P1 meter update status  = " + P1MeterUpdate)
                        SendDataToDomoticz (P1Array[4], P1MeterUpdate)

# Calculate Averages
            AveragePercentage = int(AveragePercentage // NumberOfBatteries)
            PrintToScreen("")
            PrintToScreen("   Average percentage      = " + str(AveragePercentage) + " %")
            SendDataToDomoticz (AveragePercentageIDX, str(AveragePercentage)) 
            PrintToScreen("   Combined power          = " + str(AveragePower) + " W.")
            SendDataToDomoticz (AveragePowerIDX, str(AveragePower))

class Watchdog(Exception):
    def __init__(self, timeout, userHandler=None):  # timeout in seconds
        self.timeout = timeout
        self.handler = userHandler if userHandler is not None else self.defaultHandler
        self.timer = Timer(self.timeout, self.handler)
        self.timer.start()

    def reset(self):
        self.timer.cancel()
        self.timer = Timer(self.timeout, self.handler)
        self.timer.start()

    def stop(self):
        self.timer.cancel()

    def defaultHandler(self):
        raise self

if __name__ == "__main__":
    PrintToScreen('\033c')
    create_pidfile()
    main()
Last edited by Mike70 on Monday 05 February 2024 20:43, edited 4 times in total.
willemd
Posts: 628
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: Sessy home battery script

Post by willemd »

If you want, you can integrate it with this program that optimises the use of a home battery system to achieve maximum profit, with or without a solar panel system. Have a look at this thread and the github program.
viewtopic.php?p=298562#p298562

Full explanation is on github. I have used it to simulate the use of a Sessy home battery during 2021 and 2022 in order to determine what the financial return could have been. I am currently running the program to simulate to use of a home battery (instead I am just using some devices and scripts to act as a battery system, with a svery imple made-up API).
roelvdh
Posts: 37
Joined: Saturday 18 January 2020 13:40
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.7
Location: NL
Contact:

Re: Sessy home battery script

Post by roelvdh »

That is a great script, thank you for posting. Owning 2 Sessy's I made script files sessy1.py and sessy2.py. Each one runs great at itself but obviously not together. I will not interfere in your script merging both text files, so I run both scripts alternatively for now.
njlammerts
Posts: 139
Joined: Wednesday 12 August 2020 17:13
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.2
Location: Fryslan
Contact:

Re: Sessy home battery script

Post by njlammerts »

I run my "energy" stuff (P1, gas, PV-solar) on a RPI Zero W 2. The RPI is up to date with update/upgrade and runs:

PRETTY_NAME="Raspbian GNU/Linux 10 (buster)"
NAME="Raspbian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"


When I try to install your script, it crashes during installing "sudo pip3 install numpy" it does not respond on ssh cmd and I have to kill power and reboot again.
User avatar
waltervl
Posts: 5369
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: Sessy home battery script

Post by waltervl »

"sudo pip3 install numpy" is a normal command so something is wrong with your system/OS. Buster is already an old OS so perhaps some issue there too.

Did you first run

Code: Select all

sudo apt-get update && sudo apt-get upgrade
before installing?
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
njlammerts
Posts: 139
Joined: Wednesday 12 August 2020 17:13
Target OS: Raspberry Pi / ODroid
Domoticz version: 2022.2
Location: Fryslan
Contact:

Re: Sessy home battery script

Post by njlammerts »

I did a full update & upgrade,
sudo pip3 install numpy is running now for 3 hours, at first CPU load was between 40-98% and I could use a ping from the CMD prompt. The last ping to nu.nl was 225 msec and now the whole Pi is frozen again, the domoticz page is not responding and also I cannot login with SSH .
I killed the ssh session and did a domoticz service restart, and domoticz is back again
User avatar
waltervl
Posts: 5369
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: Sessy home battery script

Post by waltervl »

You have to Google around for a solution....
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
Kedi
Posts: 561
Joined: Monday 20 March 2023 14:41
Target OS: Raspberry Pi / ODroid
Domoticz version:
Location: Somewhere in NL
Contact:

Re: Sessy home battery script

Post by Kedi »

I still have a buster system for my production Domoticz, which runs fine.
On my system with Python 3.7.3 numpy version: 1.16.2 is installed fine too.
Maybe your 512MB SDRAM is not enough.
Or like @waltervl said there is something wrong with your system/OS
Logic will get you from A to B. Imagination will take you everywhere.
roelvdh
Posts: 37
Joined: Saturday 18 January 2020 13:40
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.7
Location: NL
Contact:

Re: Sessy home battery script

Post by roelvdh »

The script runs fine but there is a thought error. Mains is only called once at the first of multiple batteries. The idea is that the first battery will contain all the mains info, but that is not necessarily correct. Various batteries can be connected to different phases. Therefore, you have to call Mains for every battery again and add the 3 phases' regenerated power over the various batteries to get correct info.

Note: This refers to an earlier version that I am still using
JanJaap
Posts: 199
Joined: Thursday 12 October 2017 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: Dev
Location: the Netherlands
Contact:

Re: Sessy home battery script

Post by JanJaap »

Their installing 2 Sessy's at the moment. No one bothered to make a plugn out of this? If not, I'll give it a go
RPi 3, Domoticz dev version, Aeon ZWave stick (with a whole bunch of slaves), Zigbee using Zigbee2MQTT, Nest thermo, P1 smart meter on RPi Zero
JanJaap
Posts: 199
Joined: Thursday 12 October 2017 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: Dev
Location: the Netherlands
Contact:

Re: Sessy home battery script

Post by JanJaap »

OK, the Sessy's are installed and doing fine (now some more sun to charge them.....) I also have a basic version of the plugin available here: JanJaapKo/SessyBattery based on the script provided in the top of this hread. Advantage: much less manual actions!

Love to hear some feedback. Functionlity will be extended a lot coming days.
RPi 3, Domoticz dev version, Aeon ZWave stick (with a whole bunch of slaves), Zigbee using Zigbee2MQTT, Nest thermo, P1 smart meter on RPi Zero
JanJaap
Posts: 199
Joined: Thursday 12 October 2017 20:46
Target OS: Raspberry Pi / ODroid
Domoticz version: Dev
Location: the Netherlands
Contact:

Re: Sessy home battery script

Post by JanJaap »

OK current version works quite decent. Gathers all power data and combines it also for all batteries (if you have them) in such a way you can add them to the energy dashboard
RPi 3, Domoticz dev version, Aeon ZWave stick (with a whole bunch of slaves), Zigbee using Zigbee2MQTT, Nest thermo, P1 smart meter on RPi Zero
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests