Hey @Burningstone ,
thanks for the quick reply.
Hmm, I have to gray out a lot , but I will take a look into.
Like I said, the script is running until it is terminated by the shell_command as I can see in the script log.
Hey @Burningstone ,
thanks for the quick reply.
Hmm, I have to gray out a lot , but I will take a look into.
Like I said, the script is running until it is terminated by the shell_command as I can see in the script log.
Attention, this is no master piece of python programming, but it worked perfectly for my needs.
I also left out some parts, that are not necessary for debugging.
#!/usr/bin/python3
## Imports
import os, sys, time
import json, requests
## wakeonlan
import struct, socket
## PID handling
import psutil
## Logging konfigurieren
import logging
logger = **defined**
headers = {
"Authorization": "Bearer xxx",
"content-type": "application/json",
}
## Funktionen definieren
# pingcheck
def check_ping(host):
ping = os.system("ping -c 1 " + host + " > /dev/null")
return(ping)
# Funktionen fuer die unterschiedlichen Geraete
def get(endpoint, entity):
url = "http://localhost:8123/api/" + endpoint + "/" + entity
response = requests.get(url, headers=headers, timeout=5)
obj = json.loads(response.text)
try:
return(str(obj['state']))
except KeyError:
return("Da stimmt etwas nicht. Existiert die entity?")
def post(endpoint, service, entity_type, entity):
url = "http://localhost:8123/api/" + endpoint + "/" + service + "/" + entity_type
data = '{"entity_id": "' + entity + '"}'
requests.post(url, headers=headers, data=data, timeout=5)
def getPowerStatus():
url = 'http://ip-of-receiver:10000/sony/system'
data = '{"method":"getPowerStatus","id":55,"params":[],"version":"1.1"}'
try:
response = requests.post(url, headers=headers, data=data, timeout=5)
obj = json.loads(response.text)
status = obj['result'][0]['status']
except KeyError:
status = 'false'
logger.error("KeyError in getPowerStatus")
except OSError:
status = 'false'
logger.error("OSError in getPowerStatus")
return status
def setPowerStatus(status):
url = 'http://ip-of-receiver:10000/sony/system'
data = '{"method":"setPowerStatus","id":55,"params":[{"status":"' + status + '"}],"version":"1.1"}'
try:
requests.post(url, headers=headers, data=data, timeout=5)
except KeyError:
status = 'false'
logger.error("KeyError in setPowerStatus")
except OSError:
status = 'false'
logger.error("OSError in setPowerStatus")
def setPlayContent(command):
try:
url = 'http://ip-of-receiver:10000/sony/avContent'
data = '{"method":"setPlayContent","id":47,"params":[{"uri":"' + command + '"}],"version":"1.2"}'
requests.post(url, headers=headers, data=data, timeout=5)
except Error as e:
logger.error(e)
def setVolume(value):
url = 'http://ip-of-receiver:10000/sony/audio'
data = '{"method":"setAudioVolume","id":98,"params":[{"volume":"' + value + '","output":""}],"version":"1.1"}'
requests.post(url, headers=headers, data=data, timeout=5)
# radio
def radio():
logger.debug("Anfang def radio")
radioready = False
standbycounter = 0
# check Sony TV status
if get('states', 'media_player.sony_bravia_tv') == 'on':
logger.debug("def radio - media_player fĂĽr TV ausgeschaltet")
post('services', 'media_player', 'turn_off', 'media_player.sony_bravia_tv')
time.sleep(1)
# check Steckdosenstatus vom Sony Receiver
if get('states', 'switch.wohnzimmer_onkyo') == 'off':
post('services', 'switch', 'turn_on', 'switch.wohnzimmer_onkyo')
logger.debug("def radio - hass Schalter fĂĽr Receiver ein geschaltet")
time.sleep(1)
## wenn der Strom an ist, prĂĽfe auf IP
while check_ping('ip-of-receiver') > 0:
logger.debug("def radio - in der ping Schleife, warten bis IP erreichbar")
time.sleep(2)
if check_ping(ip-of-receiver') == 0:
logger.debug("def radio - checkping positiv")
else:
logger.debug("def radio - checkping negativ")
logger.debug("def radio - vor der radioready Schleife")
while radioready == False:
if getPowerStatus() == 'standby' and standbycounter <= 10:
standbycounter = standbycounter + 1
time.sleep(2)
elif getPowerStatus() == 'standby' and standbycounter >= 10:
setPowerStatus('active')
radioready = True
elif getPowerStatus() == 'active':
radioready = True
# wechsle zu Radio
if radioready == True:
setPlayContent('radio:fm')
time.sleep(1)
setVolume('13')
else:
logger.debug("def radio - irgendetwas ist am Ende schief gelaufen")
# check Steckdosenstatus vom Sony TV
if get('states', 'switch.wohnzimmer_tv') == 'on':
post('services', 'switch', 'turn_off', 'switch.wohnzimmer_tv')
logger.debug("def radio - hass Schalter fĂĽr TV aus geschaltet")
time.sleep(2)
logger.debug("Ende def radio")
# prüfe ob das Skript bereits läuft, anhand der PID
## PID Variablen
pidfile = "/tmp/wzmultimedia.pid"
if os.path.isfile(pidfile):
logger.warn("%s existiert bereits..." % pidfile)
file = open(pidfile, 'r')
pid = file.read()
file.close()
if psutil.pid_exists(pid):
logger.warn("ein Prozess mit der pid: %d läuft ebenfalls, breche ab.")
sys.exit()
else:
print("Ein Prozess mit der pid %d existiert nicht, lösche %s.")
os.remove(pidfile)
pid = str(os.getpid())
open(pidfile, 'w').write(pid)
## Start der AusfĂĽhrung
try:
if len(sys.argv) <= 1:
logger.error("Da wurde kein Parameter ĂĽbergeben.")
sys.exit()
elif sys.argv[1] == 'radio':
radio()
elif sys.argv[1] == 'tv':
tv()
elif sys.argv[1] == 'aus':
aus()
else:
logger.error("Irgendwie konnte kein Parameter zugeordnet werden.")
logger.error(sys.argv)
except Exception as e:
logger.error(e)
os.unlink(pidfile)
logger.info("## Skript ist mit Exception ausgestiegen.")
finally:
os.unlink(pidfile)
logger.info("## Skript ist zuende ##")
I didn’t read the whole script, but why are you doing all this from a python script and not with a HA script? Seems overly complicated what you do.
I already used this, before I got HA.
And there are some things I have to workaround when using ha_script, like the sony api requests. Sony HA integrations are not that straight forward, when disconnecting multimedia devices from power :-).
Aaaand, the script is ready and working. The only thing that blocks it using with a shell_command is this 60s timeout. I think after 90s or so, the script is also done, but shell_command terminates it to early.
Several versions ago the “feature” was added to stop running after 1 minute. It didn’t previously have a limit. This arbitrary feature never made sense to me, and it aborts my snapshot file sync script mid file copy if multiple snapshots are pending sync. I’ve been quite mad about it but hadn’t spoken up about it yet. A timeout duration override would be an acceptable compromise, but I don’t think that was implemented.
I just opened a feature request
We ll see if it helps.
Hey @blavak68,
thanks for the link. I replied that post with my feature request
Home Assistant is not created for managing long-running external processes.
I absolutely aggre, but I think we dont want to run 30 minute scripts.
Like for my case, I have to “power on” and ping a device until it is available. Depending on the device this could last more than 60 seconds.
I just thought about another option for “shell_command”, to tell it not to wait for result, but start the external task and exit the home-assistant internal process, without touching the external process.
Just think about extending the feature request :-).
Currently the only way to reach my goal is, to split up my external script into parts and run this snippets through home-assistant internal script engine
Hi all
I found one solution to our problem
when use addon “SSH & Web Terminal”
we can our “long” shell command call
This add-on uses the hassio.addon_stdin
service to expose a shell interface to Home Assistant. This allows you to execute commands and scripts within the SSH & Web Terminal add-on, straight from Home Assistant.
This is particularly helpful when you want to execute custom scripts or commands from automations.
Example automation running my_command
:
automation:
- alias: "Example my script"
trigger:
platform: state
entity_id: binary_sensor.motion_sensor
to: "ON"
action:
service: hassio.addon_stdin
data:
addon: a0d7b954_ssh
input: "/config/scripts/my_command"
Hello @blavak68
nice solution but i have no “scripts” folder under config…dont understand what to do, can you help please?
Another workaround is to run the script in the background. AFAIK this doesn’t actually run the script in background (since there is no bg/fg), but it does cause the script to ignore SIGINT and keep chugging.
shell_command:
long_script: /script_that_runs_more_than_60_seconds.sh &
Hass will still report timeout, but the script will execute until it’s done. Not perfect, but enough for my use case.
shameless plug :
I had the same needs to run long running commands from Home Assistant.
This runs a command as a daemon (no timeout) and reports the status back on an entity’s attributes
If you are wanting to run a command in the background while avoiding the shell command timeout, one may want to try:
your_command > /dev/null 2>&1 &
When I run a python program xxxx.py
in the background, I use the following which launches the python program in the background and quickly returns control back to HA without incurring the timeout log error.
/usr/bin/env nohup python3 /config/shell_commands/xxxx.py > /dev/null 2>&1 &
That works like a charm without running into timeouts anymore, thanks a bunch mate!
Before I try that to cure my problem of a shell script timing out and crashing the automation midstream, can you tell me what that does. I don’t know any Unix.
Given that a shell is being used to run a shell command/script, the “&” at the end tells the shell that it is run the command/script in a separate (and newly created) process which frees up the shell to do other things. The “> /dev/null 2>&1
” means that if the command/script tries to send output to the display or if errors are to printed out, they are instead blocked and not printed out.
Thanks @wmaker
I’ve tested it where
command=touch /tmp/timeout && sleep 70 && touch /tmp/timeout2
but I still see an error raised
Timed out running command: `/usr/bin/env nohup ssh -i /config/.ssh/id_rsa -o 'StrictHostKeyChecking=no' [email protected] '{{ command }}' > /dev/null 2>&1 &`, after: 60s
12:00:07 AM – (ERROR) Shell Command
The command itself runs to completion with the 70 second wait
In hindsight I think I need to make the nested command run in the background too ? <— Nope wasn’t that - I still see an error but the command completes
better to modify the Shell command pyton script in /usr/local/lib/python3.xx/dist-packages/homeassistant/components/shell_command/init.py
change timeout from 60 to 120 or 240 depending how long you want to keep it live.
Will this patch survive an upgrade ?
nop! you have to modify same file after upgrade as home assistant repolace all components prior to upgrade