Run python script when HA starts

Is another instance of the script executed each time Home Assistant starts? In other words, after restarting twice, are there now two instances of the same script running in the background?

Or is there some mechanism involved that terminates the previous running instance?

I’m pretty sure it’s OK, ie there is only ever one instance of the script running at any one time. I’ve checked several times (but it is early days) and never found two instances of either script running. I think this is as expected, because when HA stops it always takes the running scripts with it, because they are running ‘inside HA’, if HA stops, then they stop. I’m going to keep an eye on this, it may depend on whether it is an orderly stop as in a manual restart from Developer Tools or a full blown crash/power cut or other mayhem. But I still incline to think it will be OK, if HA is killed by some malevolent event, it still stops, and (in my reasoning), the scripts stop with it.

Here are the running processes after a HA restart, when both scripts were running before the restart:

➜  ~ docker exec -it homeassistant bash
bash-5.1# ps
PID   USER     TIME  COMMAND
    1 root      0:00 /package/admin/s6/command/s6-svscan -d4 -- /run/service
   15 root      0:00 s6-supervise s6-linux-init-shutdownd
   17 root      0:00 /package/admin/s6-linux-init/command/s6-linux-init-shutdownd -c /run/s6/basedir -g 3000 -C -B
   24 root      0:00 s6-supervise s6rc-oneshot-runner
   25 root      0:00 s6-supervise s6rc-fdholder
   33 root      0:00 /package/admin/s6/command/s6-ipcserverd -1 -- /package/admin/s6/command/s6-ipcserver-access -v0 -E -l0 -i data/rules -- /package/admin/s6/command/s6-sudod -t 30000 -- 
   61 root      0:00 s6-supervise home-assistant
   63 root      0:17 python3 -m homeassistant --config /config
  115 root      0:00 python ./modbus/myscript1.py
  126 root      0:00 python ./modbus/myscript2.py
  127 root      0:00 bash
  133 root      0:00 ps
bash-5.1# 

As you can see, only one instance of each script is running after the restart.

BTB, this is the HACS Terminal and SSH, not the ‘Official’ one. The HACS one allows far more access including, as you can see, root access to bash, enabled by the docker exec -it homeassistant bash command.

I’ve now devised a way to this that both starts the script(s) when HA starts and restarts the script(s) if they go off-piste while HA is running. The basic idea is to use a command line sensor which detects whether the script is running, and then use a timed interval automation to restart the script if it is not running (which it isn’t when HA restarts, so that also covers the restart).

Note: you can’t use systemmonitor type process to check if the process is running because it uses psutil to get the process name and that only returns ‘python’ not ‘python ./pathto/myscript.py’ and so fails to detect the process.

Follow the steps in my earlier post up to and including step (6) but not step (7). Instead, enable the use of automations.yaml if it is not already enabled by adding this to /config/configuration.yaml:

automation: !include automations.yaml

and then (following the step numbering above):

(7) you need to enable info level logging for the system_log. Add this to /config/configuration.yaml (or just add the logs: entry/line if you already have logger:

logger:
  default: warn
  logs:
    homeassistant.components.system_log.external: info

(8) add the following to /config/configuration.yaml (if you already have sensors, remove the sensor: line below and add the rest under the existing sensor: line):

sensor:
  - platform: command_line
    name: Myscript Running State
    command: "ps -ef | grep myscript.py | grep -v grep | wc -l"

This uses the command line ps tool to check if the script is running, and returns 1 if it is, and 0 if it isn’t.

(9) add the following to /config/automations.yaml

- id: '1680200885274'
  alias: Myscript Running State (On)
  description: Checks if myscript is running
  trigger:
    - platform: time_pattern
      seconds: '30'
  condition:
    condition: numeric_state
    entity_id: sensor.myscript_running_state
    above: 0
  action:
    - service: system_log.write
      data:
        message: myscript.py is running
        level: info

- id: '1680200885275'
  alias: Myscript Running State (Off)
  description: Checks if myscript is NOT running
  trigger:
    - platform: time_pattern
      seconds: '30'
  condition:
    condition: numeric_state
    entity_id: sensor.myscript_running_state
    below: 1
  action:
    - service: system_log.write
      data:
        message: myscript.py is NOT running -> restarting...
        level: info
    - service: x_shell_command.run_myscript

This should be self-explanatory. Each entry needs a unique numeric id, doesn’t matter what it is as long as it is unique. The first automation deals with the is running state, the second with the is not running state. In each case, the time_pattern triggers it to run every 30 seconds after the start of the minute, the condition checks the sensor to see whether it is 0 (not running) or 1 (running) and then takes the appropriate action.

The first automation is just a nicety that gives you logged confirmation the script is running. Bin it if you don’t want it.

(10) do a configuration check and if you get the green light go ahead and restart HA and check all is well. If your code fails the configuration check, note the error(s), correct them, and try again.

One way to find a workaround to that limitation of 60 seconds is to spawn the procedure from the shell command… Example for running “test.sh”:

Create a shell command like this (example with arguments passed to the shell script):

shell_command:
   test: /bin/bash /config/test_ini.sh "{{ arguments }}"

The test_ini.sh is very simple (test.sh is the shell script taking more than 60 seconds to run…):

#!/bin/bash
#
#
bash /config/test.sh "$1" &> /config/test.log &

The “_ini” shell will submit (spawn) the test.sh but will not wait the end of that execution of that script and will close immediately after the submission… The test.sh will run like a batch job…
The shell script will execute in the HA container without the 60 seconds limit…

The other way is to submit the procedure in a SSH terminal has explained before (this option even allow to access commands not available within the HA container but allowed/installed in a SSH terminal, see my answer above):

shell_command:
   test: ssh Your_SSH_Username@HA_IP_Adrress -o 'StrictHostKeyChecking=no' -i /config/.ssh/id_rsa '/bin/bash /config/test_ini.sh "{{ arguments }}"'

Make sure your procedure is well tested and will not run for ever while consuming a lot of CPU…:wink:

1 Like

@browetd - thanks for adding this, always good to have alternative methods.

I’m pretty sure my method doesn’t cause this sort of problem. There is only ever one instance of the script running (at least so far), and CPU use is as before and stable.

I am using the “_ini.sh” “workaround” to read SMS from my modem… The procedure is waiting for a new SMS to come in, so that procedure is running since HA starts and forever… but it is just waiting most of the time…

Can you confirm/refute the following thought:

I suspect that spawning the process in the shell created via ssh will mean it will not be terminated when Home Assistant restarts because that shell is executing outside of Home Assistant’s docker container. Therefore each time Home Assistant restarts, it will create another running instance of the script. Only a restart of the SSH & Web Terminal Add-on, or reboot, would eliminate the script(s) running in the background.

Is that right or wrong?

@123 To be tested as I never tried to submit via SSH a “never ending” script… I am only doing that in the HA container with only one script (which is (as I mentionned) waiting for a new SMS coming in) and never had any problem in this case…

That’s the reason why I mentionned that you have to be carefull about those workarounds and test them very extensively and seriously before launching it into production…

running into a deadend … need some help on this:

I have a .py script that reads some data from an erergymanager and send it via mqtt to HA. on studioCodeServer Terminal the scripts works just as expected.

#
# Copyright: Kilian Knoll, 15.12.2018
# Update: Feb 12 2020: Publish to MQTT
# Utility to parse EnergyManager EM300LR using the JSON API
#
#
#  
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#  Please note that any incorrect or careless usage of this module as well as errors in the implementation can damage your Energy Manager!
#  Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this module, examples or mentioned information.
#  Thus, use it at your own risk!
#
#
#  Purpose: 
#  Returns:
#     Returnvalue: 0    (Everything all right)
#     Returnvalue: -1   (Crap happened)
#     em300data:        (Empty list in case Returnvalue =-1)
#     em300data:        (Full list of key-value pairs in case Returnvalue = 0)
#
# Tested with:
#           python 3.5, 3,7
#           B-control Energy Manager EM300, Firmware Version 2.04
# Based on: https://www.tq-automation.com/Service-Support/Downloads/Downloads-Energiemanagement
# Using the JSON Documentation: https://www.tq-automation.com/content/download/10996/file/TQ%20Energy%20Manager%20-%20JSON-API.0104.pdf
#

# Please change the following values to reflect your environment:
Em_IP_Adress = "192.168.0.23"
EM_Serialumber= "72102414"							#Serial Number can be found accessing the Energy Manager´s Web Page under  Settings - Serial number
EM_Password= ""						    #This is the password you have specified on the Energy Manager´s Web Page (without quotes)
MQTTBroker_IPaddress="192.168.0.118"        #You need to have an MQTT broker set up & running
MQTTBroker_USERNAME="mqtt-user"
MQTTBroker_PASSWORD="2MqTT-User"
# End Configurable Parameters 
#
import requests
import time 
import json
import datetime
import logging      #from loggerdate import loggerdate
from pprint import pprint
import paho.mqtt.client as mqtt
import sys

myparams= {'login': EM_Serialumber, 'password': EM_Password, 'save_login': '1'}

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; "
}
mySession = requests.Session()

def changeobiskeys(myjsoninput):
    myjsoninput["Active power_incoming"] =  myjsoninput.pop("1-0:1.4.0*255")
    myjsoninput["Active energy_incoming"] =  myjsoninput.pop("1-0:1.8.0*255")
    myjsoninput["Apparent power-"] =  myjsoninput.pop("1-0:10.4.0*255")
    myjsoninput["Apparent energy-"] =  myjsoninput.pop("1-0:10.8.0*255")
    myjsoninput["Power factor"] =  myjsoninput.pop("1-0:13.4.0*255")
    myjsoninput["Supply frequency"] =  myjsoninput.pop("1-0:14.4.0*255")
    myjsoninput["Active power- "] =  myjsoninput.pop("1-0:2.4.0*255")
    myjsoninput["Active energy-"] =  myjsoninput.pop("1-0:2.8.0*255")
    myjsoninput["Active power_incoming L1"] =  myjsoninput.pop("1-0:21.4.0*255")
    myjsoninput["Active energy_incoming L1"] =  myjsoninput.pop("1-0:21.8.0*255")
    myjsoninput["Active power- L1"] =  myjsoninput.pop("1-0:22.4.0*255")
    myjsoninput["Active energy- L1"] =  myjsoninput.pop("1-0:22.8.0*255")
    myjsoninput["Reactive power_incoming L1"] =  myjsoninput.pop("1-0:23.4.0*255")
    myjsoninput["Reactive energy_incoming L1"] =  myjsoninput.pop("1-0:23.8.0*255")
    myjsoninput["Reactive power- L1"] =  myjsoninput.pop("1-0:24.4.0*255")
    myjsoninput["Reactive energy- L1"] =  myjsoninput.pop("1-0:24.8.0*255")
    myjsoninput["Apparent power_incoming L1"] =  myjsoninput.pop("1-0:29.4.0*255")
    myjsoninput["Apparent energy_incoming L1"] =  myjsoninput.pop("1-0:29.8.0*255")
    myjsoninput["Reactive power_incoming"] =  myjsoninput.pop("1-0:3.4.0*255")
    myjsoninput["Reactive energy_incoming"] =  myjsoninput.pop("1-0:3.8.0*255")
    myjsoninput["Apparent power- L1"] =  myjsoninput.pop("1-0:30.4.0*255")
    myjsoninput["Apparent energy- L1"] =  myjsoninput.pop("1-0:30.8.0*255")
    myjsoninput["Current L1"] =  myjsoninput.pop("1-0:31.4.0*255")
    myjsoninput["Voltage L1"] =  myjsoninput.pop("1-0:32.4.0*255")
    myjsoninput["Power factor L1"] =  myjsoninput.pop("1-0:33.4.0*255")
    myjsoninput["Reactive power-"] =  myjsoninput.pop("1-0:4.4.0*255")
    myjsoninput["Reactive energy-"] =  myjsoninput.pop("1-0:4.8.0*255")
    myjsoninput["Active power_incoming L2"] =  myjsoninput.pop("1-0:41.4.0*255")
    myjsoninput["Active energy_incoming L2"] =  myjsoninput.pop("1-0:41.8.0*255")
    myjsoninput["Active power- L2"] =  myjsoninput.pop("1-0:42.4.0*255")
    myjsoninput["Active energy- L2"] =  myjsoninput.pop("1-0:42.8.0*255")
    myjsoninput["Reactive power_incoming L2"] =  myjsoninput.pop("1-0:43.4.0*255")
    myjsoninput["Reactive energy_incoming L2"] =  myjsoninput.pop("1-0:43.8.0*255")
    myjsoninput["Reactive power- L2"] =  myjsoninput.pop("1-0:44.4.0*255")
    myjsoninput["Reactive energy- L2"] =  myjsoninput.pop("1-0:44.8.0*255")
    myjsoninput["Apparent power_incoming L2"] =  myjsoninput.pop("1-0:49.4.0*255")
    myjsoninput["Apparent energy_incoming L2"] =  myjsoninput.pop("1-0:49.8.0*255")
    myjsoninput["Apparent power- L2"] =  myjsoninput.pop("1-0:50.4.0*255")
    myjsoninput["Apparent energy- L2"] =  myjsoninput.pop("1-0:50.8.0*255")
    myjsoninput["Current L2"] =  myjsoninput.pop("1-0:51.4.0*255")
    myjsoninput["Voltage L2"] =  myjsoninput.pop("1-0:52.4.0*255")
    myjsoninput["Power factor L2"] =  myjsoninput.pop("1-0:53.4.0*255")
    myjsoninput["Active power_incoming L3"] =  myjsoninput.pop("1-0:61.4.0*255")
    myjsoninput["Active energy_incoming L3"] =  myjsoninput.pop("1-0:61.8.0*255")
    myjsoninput["Active power- L3"] =  myjsoninput.pop("1-0:62.4.0*255")
    myjsoninput["Active energy- L3"] =  myjsoninput.pop("1-0:62.8.0*255")
    myjsoninput["Reactive power_incoming L3"] =  myjsoninput.pop("1-0:63.4.0*255")
    myjsoninput["Reactive energy_incoming L3"] =  myjsoninput.pop("1-0:63.8.0*255")
    myjsoninput["Reactive power- L3"] =  myjsoninput.pop("1-0:64.4.0*255")
    myjsoninput["Reactive energy- L3"] =  myjsoninput.pop("1-0:64.8.0*255")
    myjsoninput["Apparent power_incoming L3"] =  myjsoninput.pop("1-0:69.4.0*255")
    myjsoninput["Apparent energy_incoming L3"] =  myjsoninput.pop("1-0:69.8.0*255")
    myjsoninput["Apparent power- L3"] =  myjsoninput.pop("1-0:70.4.0*255")
    myjsoninput["Apparent energy- L3"] =  myjsoninput.pop("1-0:70.8.0*255")
    myjsoninput["Current L3"] =  myjsoninput.pop("1-0:71.4.0*255")
    myjsoninput["Voltage L3"] =  myjsoninput.pop("1-0:72.4.0*255")
    myjsoninput["Power factor L3"] =  myjsoninput.pop("1-0:73.4.0*255")
    myjsoninput["Apparent power_incoming"] =  myjsoninput.pop("1-0:9.4.0*255")
    myjsoninput["Apparent energy_incoming"] =  myjsoninput.pop("1-0:9.8.0*255")
    #serial
    #status
    return myjsoninput

def readenergymanager():
    try:
        #------------------------------------------------------------
        #Start Connection to Energymanager 
            
        #------------------------------------------------------------
        # Initial handshake
        print ("starting initial handshake - start step 1 ...")
        r1 = mySession.get('http://'+ Em_IP_Adress + '/start.php',  headers=headers)
        if (r1.status_code == requests.codes.ok):
            pass
        else:
            Error_Connecting = r1.status_code
            print ("Unable to connect :", Error_Connecting)
    except Exception as Error_ConnecttoEnergymanager:
        print ("Error accessing Energy Manager step1 :", Error_ConnecttoEnergymanager)		
        time.sleep(0.25)
        #------------------------------------------------------------
        # Authenticate with credentials
    try:    
        print ("trying to authenticate -start step 2 ...")
        r2 = mySession.post('http://'+ Em_IP_Adress + '/start.php',myparams,  headers=headers)
        if (r2.status_code == requests.codes.ok):
            pass
        else:
            Error_Connecting = r2.status_code
            print ("Unable to Authenticate :", Error_Connecting)   
    except Exception as Error_ConnecttoEnergymanager:
        print ("Error accessing Energy Manager step2 :", Error_ConnecttoEnergymanager)	        
        #------------------------------------------------------------
        # Get Data from EnergyManager
    try:
        print ("trying to get data - start step 3 ...")
        r3 = mySession.get('http://'+ Em_IP_Adress +'/mum-webservice/data.php',  headers=headers)
        if (r3.status_code == requests.codes.ok):
            pass
        else:
            Error_Connecting = r3.status_code
            print ("Unable to Get data :", Error_Connecting)             
        em300data=json.loads(r3.text)
        Error_Connecting = 0

    except Exception as Error_ConnecttoEnergymanager:
        print ("Error accessing Energy Manager step3 :", Error_ConnecttoEnergymanager)
        #logging.error("%s %s %s", loggerdate(), ",readenergymanager: Ran into exception querying the energymanager : ", Error_ConnecttoEnergymanager)
        Error_Connecting=Error_ConnecttoEnergymanager

        #
        # End Connection to EnergyManager
        #_______________________________________________________________
    # 
    #--------------------------------------------------------------
    # Processing data
    Returnvalue = -1
    if (Error_Connecting == 0):
        if (len(em300data) >1):                         # We have something in the list
            if (em300data["status"] == 0):                  # We got valid data from Energymanager
                ("before calling changeobiskeys")
                em300data =changeobiskeys(em300data)
                Returnvalue =0
    else:                                               # We ran into trouble and allocate an empty list
        em300data={}
        print ("Issue getting data from EnergyManager ", Error_Connecting)
        
    return (Returnvalue, em300data)    
    


if __name__ == "__main__":  
    emclient = mqtt.Client("emclient")                                          #create new instance
    emclient.username_pw_set(MQTTBroker_USERNAME, MQTTBroker_PASSWORD)
    emclient.connect(MQTTBroker_IPaddress)
    
    print ("Start querying Energy Manager....")
    try:
        Myreturnvalue, Mydata = readenergymanager();
        if (Myreturnvalue == 0):
            print ("Returnvalue -should be zero if successful : ", Myreturnvalue)
            print ("----------------Start Values from Energy Manager ----------------")
            pprint (Mydata)
            print ("----------------End - Values from Energy Manager ----------------")	
            print ("Two Specific values from array....")
            print ("Energy to Grid   (Obis code: 1-0:2.8.0)", Mydata['Active energy-'])
            print ("Energy from Grid (Obis code: 1-0:1.8.0)", Mydata['Active energy_incoming'])
            print ("----------------End - Two Specific values from array ------------")   
            params = Mydata.keys()
            print ("----------------Publishing to MQTT  ------------")
            for p in sorted(params):
                print("PublishtoMQTT:","{:{width}}: {}".format(p, Mydata[p], width=len(max(params, key=len))))
                TOPIC = ("Energymanager/"+p)
                emclient.publish(TOPIC,Mydata[p]) 
            print ("----------------END Publishing to MQTT  --------")
        else:
            print ("I was unable to query the Energy Manager")
    except Exception as ex:
        print ("Issues querying EnergyManager :", ex)

                        

But how to get it running on HA-automation calling?

Reading a lot at this community I am on a dead end and need some help from you.

as mentioned at our aproach I created the file: /config/pyscript/run_readenergymanager.py

@service
def run_readenergymanager():
    import sys
    if "/config/pyscript/modules" not in sys.path:
        sys.path.append("/config/pyscript/modules")
    import readenergymanager   
    readenergymanager.mainline()

and /config/pyscript/modules/readenergymanager.py

with:

#
# Copyright: Kilian Knoll, 15.12.2018
# Update: Feb 12 2020: Publish to MQTT
# Utility to parse EnergyManager EM300LR using the JSON API
#
#
#  
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#
#  Please note that any incorrect or careless usage of this module as well as errors in the implementation can damage your Energy Manager!
#  Therefore, the author does not provide any guarantee or warranty concerning to correctness, functionality or performance and does not accept any liability for damage caused by this module, examples or mentioned information.
#  Thus, use it at your own risk!
#
#
#  Purpose: 
#  Returns:
#     Returnvalue: 0    (Everything all right)
#     Returnvalue: -1   (Crap happened)
#     em300data:        (Empty list in case Returnvalue =-1)
#     em300data:        (Full list of key-value pairs in case Returnvalue = 0)
#
# Tested with:
#           python 3.5, 3,7
#           B-control Energy Manager EM300, Firmware Version 2.04
# Based on: https://www.tq-automation.com/Service-Support/Downloads/Downloads-Energiemanagement
# Using the JSON Documentation: https://www.tq-automation.com/content/download/10996/file/TQ%20Energy%20Manager%20-%20JSON-API.0104.pdf
#
# Please change the following values to reflect your environment:
Em_IP_Adress = "192.168.0.23"
EM_Serialumber= "72102414"							#Serial Number can be found accessing the Energy Manager´s Web Page under  Settings - Serial number
EM_Password= ""						    #This is the password you have specified on the Energy Manager´s Web Page (without quotes)
MQTTBroker_IPaddress="192.168.0.118"        #You need to have an MQTT broker set up & running
MQTTBroker_USERNAME="mqtt-user"
MQTTBroker_PASSWORD="2MqTT-User"
# End Configurable Parameters 
#
@pyscript_executor
def mainline():
    import requests
    import time 
    import json
    import datetime
    import logging      #from loggerdate import loggerdate
    from pprint import pprint
    import paho.mqtt.client as mqtt
    import sys

    myparams= {'login': EM_Serialumber, 'password': EM_Password, 'save_login': '1'}

    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; "
    }
    mySession = requests.Session()

def changeobiskeys(myjsoninput):
    myjsoninput["Active power_incoming"] =  myjsoninput.pop("1-0:1.4.0*255")
    myjsoninput["Active energy_incoming"] =  myjsoninput.pop("1-0:1.8.0*255")
    myjsoninput["Apparent power-"] =  myjsoninput.pop("1-0:10.4.0*255")
    myjsoninput["Apparent energy-"] =  myjsoninput.pop("1-0:10.8.0*255")
    myjsoninput["Power factor"] =  myjsoninput.pop("1-0:13.4.0*255")
    myjsoninput["Supply frequency"] =  myjsoninput.pop("1-0:14.4.0*255")
    myjsoninput["Active power- "] =  myjsoninput.pop("1-0:2.4.0*255")
    myjsoninput["Active energy-"] =  myjsoninput.pop("1-0:2.8.0*255")
    myjsoninput["Active power_incoming L1"] =  myjsoninput.pop("1-0:21.4.0*255")
    myjsoninput["Active energy_incoming L1"] =  myjsoninput.pop("1-0:21.8.0*255")
    myjsoninput["Active power- L1"] =  myjsoninput.pop("1-0:22.4.0*255")
    myjsoninput["Active energy- L1"] =  myjsoninput.pop("1-0:22.8.0*255")
    myjsoninput["Reactive power_incoming L1"] =  myjsoninput.pop("1-0:23.4.0*255")
    myjsoninput["Reactive energy_incoming L1"] =  myjsoninput.pop("1-0:23.8.0*255")
    myjsoninput["Reactive power- L1"] =  myjsoninput.pop("1-0:24.4.0*255")
    myjsoninput["Reactive energy- L1"] =  myjsoninput.pop("1-0:24.8.0*255")
    myjsoninput["Apparent power_incoming L1"] =  myjsoninput.pop("1-0:29.4.0*255")
    myjsoninput["Apparent energy_incoming L1"] =  myjsoninput.pop("1-0:29.8.0*255")
    myjsoninput["Reactive power_incoming"] =  myjsoninput.pop("1-0:3.4.0*255")
    myjsoninput["Reactive energy_incoming"] =  myjsoninput.pop("1-0:3.8.0*255")
    myjsoninput["Apparent power- L1"] =  myjsoninput.pop("1-0:30.4.0*255")
    myjsoninput["Apparent energy- L1"] =  myjsoninput.pop("1-0:30.8.0*255")
    myjsoninput["Current L1"] =  myjsoninput.pop("1-0:31.4.0*255")
    myjsoninput["Voltage L1"] =  myjsoninput.pop("1-0:32.4.0*255")
    myjsoninput["Power factor L1"] =  myjsoninput.pop("1-0:33.4.0*255")
    myjsoninput["Reactive power-"] =  myjsoninput.pop("1-0:4.4.0*255")
    myjsoninput["Reactive energy-"] =  myjsoninput.pop("1-0:4.8.0*255")
    myjsoninput["Active power_incoming L2"] =  myjsoninput.pop("1-0:41.4.0*255")
    myjsoninput["Active energy_incoming L2"] =  myjsoninput.pop("1-0:41.8.0*255")
    myjsoninput["Active power- L2"] =  myjsoninput.pop("1-0:42.4.0*255")
    myjsoninput["Active energy- L2"] =  myjsoninput.pop("1-0:42.8.0*255")
    myjsoninput["Reactive power_incoming L2"] =  myjsoninput.pop("1-0:43.4.0*255")
    myjsoninput["Reactive energy_incoming L2"] =  myjsoninput.pop("1-0:43.8.0*255")
    myjsoninput["Reactive power- L2"] =  myjsoninput.pop("1-0:44.4.0*255")
    myjsoninput["Reactive energy- L2"] =  myjsoninput.pop("1-0:44.8.0*255")
    myjsoninput["Apparent power_incoming L2"] =  myjsoninput.pop("1-0:49.4.0*255")
    myjsoninput["Apparent energy_incoming L2"] =  myjsoninput.pop("1-0:49.8.0*255")
    myjsoninput["Apparent power- L2"] =  myjsoninput.pop("1-0:50.4.0*255")
    myjsoninput["Apparent energy- L2"] =  myjsoninput.pop("1-0:50.8.0*255")
    myjsoninput["Current L2"] =  myjsoninput.pop("1-0:51.4.0*255")
    myjsoninput["Voltage L2"] =  myjsoninput.pop("1-0:52.4.0*255")
    myjsoninput["Power factor L2"] =  myjsoninput.pop("1-0:53.4.0*255")
    myjsoninput["Active power_incoming L3"] =  myjsoninput.pop("1-0:61.4.0*255")
    myjsoninput["Active energy_incoming L3"] =  myjsoninput.pop("1-0:61.8.0*255")
    myjsoninput["Active power- L3"] =  myjsoninput.pop("1-0:62.4.0*255")
    myjsoninput["Active energy- L3"] =  myjsoninput.pop("1-0:62.8.0*255")
    myjsoninput["Reactive power_incoming L3"] =  myjsoninput.pop("1-0:63.4.0*255")
    myjsoninput["Reactive energy_incoming L3"] =  myjsoninput.pop("1-0:63.8.0*255")
    myjsoninput["Reactive power- L3"] =  myjsoninput.pop("1-0:64.4.0*255")
    myjsoninput["Reactive energy- L3"] =  myjsoninput.pop("1-0:64.8.0*255")
    myjsoninput["Apparent power_incoming L3"] =  myjsoninput.pop("1-0:69.4.0*255")
    myjsoninput["Apparent energy_incoming L3"] =  myjsoninput.pop("1-0:69.8.0*255")
    myjsoninput["Apparent power- L3"] =  myjsoninput.pop("1-0:70.4.0*255")
    myjsoninput["Apparent energy- L3"] =  myjsoninput.pop("1-0:70.8.0*255")
    myjsoninput["Current L3"] =  myjsoninput.pop("1-0:71.4.0*255")
    myjsoninput["Voltage L3"] =  myjsoninput.pop("1-0:72.4.0*255")
    myjsoninput["Power factor L3"] =  myjsoninput.pop("1-0:73.4.0*255")
    myjsoninput["Apparent power_incoming"] =  myjsoninput.pop("1-0:9.4.0*255")
    myjsoninput["Apparent energy_incoming"] =  myjsoninput.pop("1-0:9.8.0*255")
    #serial
    #status
    return myjsoninput

def readenergymanager():
    try:
        #------------------------------------------------------------
        #Start Connection to Energymanager 
            
        #------------------------------------------------------------
        # Initial handshake
        print ("starting initial handshake - start step 1 ...")
        r1 = mySession.get('http://'+ Em_IP_Adress + '/start.php',  headers=headers)
        if (r1.status_code == requests.codes.ok):
            pass
        else:
            Error_Connecting = r1.status_code
            print ("Unable to connect :", Error_Connecting)
    except Exception as Error_ConnecttoEnergymanager:
        print ("Error accessing Energy Manager step1 :", Error_ConnecttoEnergymanager)		
        time.sleep(0.25)
        #------------------------------------------------------------
        # Authenticate with credentials
    try:    
        print ("trying to authenticate -start step 2 ...")
        r2 = mySession.post('http://'+ Em_IP_Adress + '/start.php',myparams,  headers=headers)
        if (r2.status_code == requests.codes.ok):
            pass
        else:
            Error_Connecting = r2.status_code
            print ("Unable to Authenticate :", Error_Connecting)   
    except Exception as Error_ConnecttoEnergymanager:
        print ("Error accessing Energy Manager step2 :", Error_ConnecttoEnergymanager)	        
        #------------------------------------------------------------
        # Get Data from EnergyManager
    try:
        print ("trying to get data - start step 3 ...")
        r3 = mySession.get('http://'+ Em_IP_Adress +'/mum-webservice/data.php',  headers=headers)
        if (r3.status_code == requests.codes.ok):
            pass
        else:
            Error_Connecting = r3.status_code
            print ("Unable to Get data :", Error_Connecting)             
        em300data=json.loads(r3.text)
        Error_Connecting = 0

    except Exception as Error_ConnecttoEnergymanager:
        print ("Error accessing Energy Manager step3 :", Error_ConnecttoEnergymanager)
        #logging.error("%s %s %s", loggerdate(), ",readenergymanager: Ran into exception querying the energymanager : ", Error_ConnecttoEnergymanager)
        Error_Connecting=Error_ConnecttoEnergymanager

        #
        # End Connection to EnergyManager
        #_______________________________________________________________
    # 
    #--------------------------------------------------------------
    # Processing data
    Returnvalue = -1
    if (Error_Connecting == 0):
        if (len(em300data) >1):                         # We have something in the list
            if (em300data["status"] == 0):                  # We got valid data from Energymanager
                ("before calling changeobiskeys")
                em300data =changeobiskeys(em300data)
                Returnvalue =0
    else:                                               # We ran into trouble and allocate an empty list
        em300data={}
        print ("Issue getting data from EnergyManager ", Error_Connecting)
        
    return (Returnvalue, em300data)    
    


if __name__ == "__main__":  
    emclient = mqtt.Client("emclient")                                          #create new instance
    emclient.username_pw_set(MQTTBroker_USERNAME, MQTTBroker_PASSWORD)
    emclient.connect(MQTTBroker_IPaddress)
    
    print ("Start querying Energy Manager....")
    try:
        Myreturnvalue, Mydata = readenergymanager();
        if (Myreturnvalue == 0):
            print ("Returnvalue -should be zero if successful : ", Myreturnvalue)
            print ("----------------Start Values from Energy Manager ----------------")
            pprint (Mydata)
            print ("----------------End - Values from Energy Manager ----------------")	
            print ("Two Specific values from array....")
            print ("Energy to Grid   (Obis code: 1-0:2.8.0)", Mydata['Active energy-'])
            print ("Energy from Grid (Obis code: 1-0:1.8.0)", Mydata['Active energy_incoming'])
            print ("----------------End - Two Specific values from array ------------")   
            params = Mydata.keys()
            print ("----------------Publishing to MQTT  ------------")
            for p in sorted(params):
                print("PublishtoMQTT:","{:{width}}: {}".format(p, Mydata[p], width=len(max(params, key=len))))
                TOPIC = ("Energymanager/"+p)
                emclient.publish(TOPIC,Mydata[p]) 
            print ("----------------END Publishing to MQTT  --------")
        else:
            print ("I was unable to query the Energy Manager")
    except Exception as ex:
        print ("Issues querying EnergyManager :", ex)

                        

calling the service:

Pyscript Python scripting: run_readenergymanager

i get only the log entry:

2023-12-15 12:49:08.935 DEBUG (MainThread) [custom_components.pyscript.eval] file.run_readenergymanager.run_readenergymanager: calling mainline(, {})

but no new readings

What am I doing wrong? I welcome any form of help to solve the problem and get the script running.

@Monster_D Did you found a solution for your problem. Because I’m standing may be on the same script problem. That’s the first time that I’m using phyton scripts on HA.

I use the same python script. It is working on the Sudio Code Server on HA and I get the mqtt messages, thats fine. But if I want to start it by services, I get every time an failure on the protcoll:

ERROR (SyncWorker_14) [homeassistant.components.python_script] Error loading script energymeterreadout.py: Line 202: “name” is an invalid variable name because it starts with “_”

Unfortunately I was not able to solve the issue. So for now I am running the script as cron job forum another Linux based system.