Wilf schreef op dinsdag 28 juli 2020 @ 23:27:
Ik heb gisteravond/nacht m'n hoofd gebroken, het forum van HA doorgeplozen, de manuals, voorbeelden et cetera et cetera maar ik krijg het volgende niet voor elkaar:
Ik wil een slider value sturen naar een shell command. En dat werkt niet.
Hier laat ik zien wat ik allemaal al heb geprobeerd en wat wel en niet werkt.
Eerst mijn huidige setting (met wat ghosts die ik geprobeerd heb en niet allemaal meer functioneel zijn):
Deel van automations.yaml
YAML:
1
2
3
4
5
6
7
8
9
10
11
12
13
| - id: 'xxxxxxxxxxx'
alias: Volume mediabak
trigger:
- entity_id: input_number.vol_bak
platform: state
action:
- service: shell_command.volume_mediabak
data_template:
vol_data: "{{ '%s' % states('input_number.vol_bak') }}"
- service: input_text.set_value
data_template:
entity_id: input_text.tekstveld
value: "{{'%s' % (states('input_number.vol_bak').split('.')[0]) }}" |
Ik heb verscheidene tests gedaan; in deze laatste versie heb ik geprobeerd het getal eerst in een tekstbestand te zetten en dat vervolgens op te vragen in de shell_command. Eerder heb ik ook direct de data geprobeerd over te zetten vanuit input_number maar dat maakte niets uit. Dat ik dit deed is hier te zien aan het feit dat ik zowel een variabele alsmede een tekstveld vul.
Deel van configuration.yaml
YAML:
1
2
3
4
5
6
7
8
9
10
11
| input_number:
vol_bak:
name: "Volume Mediabak"
initial: 0
min: 0
max: 100
step: 1
shell_command:
volume_mediabak: "echo -n 'volume {{ states(''input_text.tekstveld'') }}' | nc -u -w1 192.168.12.34 54321"
# {{states(''input_number.volume_mediabak'')}} {{states(''input_number.vol_bak'')}} {{vol_data}} |
Ondanks dat ik wel tig verschillende manieren heb geprobeerd staan hier als comment de paar voorgaande voor de 'foutieve' die ik als laatst heb geprobeerd. Deze laatste, 'foutieve', noem ik foutief omdat deze tenminste een error gooit waar andere pogingen geen errors in de logs vertoonden maar simpelweg het shell command wegstuurden en er niets gebeurde.
Wat heb ik allemaal geprobeerd?
- Allerlei verschillende combinaties en uitwisselingen van quotes; haalt niks uit.
- Een vaste waarde in plaats van de variabele; werkt perfect!
- Verschillende manieren om een variabele in te voegen; haalt niks uit.
Hier een aantal tests in templates onder de Dev-tools:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
| 'echo -n "volume {{ states('input_number.vol_bak').split('.')[0] }}" | nc -u -w1 192.168.12.34 54321'
'echo -n "volume {{ states('input_number.vol_bak').split('.')[0] }}" | nc -u -w1 192.168.12.34 54321'
"echo -n "volume {{ states('input_number.vol_bak').split('.')[0] }}" | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume {{'%s' % (states('input_number.vol_bak').split('.')[0]) }}'' | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume {{ states('input_number.vol_bak').split('.')[0] | int }}'' | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume {{ states('input_number.vol_bak').split('.')[0] }}'' | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume {{ states('input_text.tekstveld') }}'' | nc -u -w1 192.168.12.34 54321"
{{ states("input_number.vol_bak") }}
{{ states("input_number.vol_bak").split('.')[0] }}
"echo -n 'volume {{ states('vol_data') }}' | nc -u -w1 192.168.12.34 54321"
"echo -n 'volume {{ vol_data }}' | nc -u -w1 192.168.12.34 54321" |
Uiteraard expres een paar waarvan ik bijna wel zeker wist dat ze niet zouden gaan werken. Uitkomst van bovenstaande test templates:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
| 'echo -n "volume 80" | nc -u -w1 192.168.12.34 54321'
'echo -n "volume 80" | nc -u -w1 192.168.12.34 54321'
"echo -n "volume 80" | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume 80'' | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume 80'' | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume 80'' | nc -u -w1 192.168.12.34 54321"
"echo -n ''volume 80'' | nc -u -w1 192.168.12.34 54321"
80.0
80
"echo -n 'volume unknown' | nc -u -w1 192.168.12.34 54321"
"echo -n 'volume ' | nc -u -w1 192.168.12.34 54321" |
De laatste zijn logischerwijs stuk omdat deze verwijzen naar een stukje data binnen een automation.
Oh en in het begin van de avond gister had ik geen string methods gebruikt zoals split maar ik moet echt een getal van 0 tot 100 hebben en dan in stringformaat, geen int of float. Al heb ik zelfs dat geprobeerd (pipen door int of pipen naar andere methods). Alle topics op HA die ook maar iets met deze soort data transfer te maken hebben heb ik geprobeerd. Ook kwam ik daar tegen dat het parsen van data vanuit een automation naar shell_command niet officieel kan dus 'may or may not work' dus had ik zelfs nog een tekstveld gemaakt die vervolgens in de shell_command in de configuration.yaml uitgelezen werd. En dus een input in de config zelf. Maar ook daar: no dice.
*Ik had overigens eerst de automation en de input number netjes gemaakt via de GUI maar die werkte niet; die heb ik toen uitgeschakeld en zijn helemaal verdwenen. Kan ik deze nog ergens terughalen (die staan niet in de configuration.yaml en automations.yaml namelijk) zodat ik deze corpses ook kan opruimen? Ik word altijd een beetje onrustig van het idee dat er ergens in de code allemaal lijken liggen die alleen maar resources aan het vreten zijn (of dat nou extra parsingtijd of alleen bits zijn maakt me dan niet eens zo veel uit).
Overigens, de huidige setup geeft een error; eerdere tests gaven geen error maar stuurde simpelweg geen bericht naar buiten (extra frustrerend; er zit dan niks fouts in je script maar de error zit dan in wezen in de shell parsing / stdout)... De huidige error is dan ook:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| Error rendering command template: TemplateSyntaxError: expected token ',', got 'input_text'
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 198, in ensure_valid
self._compiled_code = self._env.compile(self.template)
File "/usr/local/lib/python3.8/site-packages/jinja2/environment.py", line 638, in compile
self.handle_exception(source=source_hint)
File "/usr/local/lib/python3.8/site-packages/jinja2/environment.py", line 832, in handle_exception
reraise(*rewrite_traceback_stack(source=source))
File "/usr/local/lib/python3.8/site-packages/jinja2/_compat.py", line 28, in reraise
raise value.with_traceback(tb)
File "<unknown>", line 1, in template
jinja2.exceptions.TemplateSyntaxError: expected token ',', got 'input_text'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/src/homeassistant/homeassistant/components/shell_command/__init__.py", line 46, in async_service_handler
rendered_args = args_compiled.async_render(service.data)
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 223, in async_render
compiled = self._compiled or self._ensure_compiled()
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 297, in _ensure_compiled
self.ensure_valid()
File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 200, in ensure_valid
raise TemplateError(err)
homeassistant.exceptions.TemplateError: TemplateSyntaxError: expected token ',', got 'input_text' |
Maar eigenlijk is deze error dus bijzaak omdat eerdere errorloze var includes wél foutloos werkten (afgezien dus van het daadwerkelijk uitvoeren van de code op de server).
Omdat ik hier serieus mijn hele avond en nacht op heb stukgeslagen was ik bij deze iteratie maar geëindigd en heb ik niet de 'foutloze' (maar niet werkende) versies teruggezet. Maar elke keer als ik dus gewoon een getal intyp in plaats van een variabele dan werkt het command wel prima.
Ik ben vastgelopen, dus iemand die wel succesvol een variabele naar een shell command heeft weten te sturen, enlighten me. Ik ben op dit moment een schilder die vlak voor zijn doek staat en geen atelier meer heeft om 30 meter naar achter te lopen om het gehele plaatje te overzien om zo een obvious error in het grotere plaatje op te vallen (polderblindheid in programmeren is ook een dingetje

)
Ik ben alweer een stapje verder door te debuggen. Helaas laat debug niet de goede string zien (ofwel: debug geeft alleen maar aan wanneer iets niet werkt

) maar ik weet nu wel waar de fout zit.
- Als ik geen variabele gebruik dan komen de berichten gewoon aan. Debug blijft leeg.
- Als ik een variabele gebruik zie ik in de debug dat de string in wezen werkt maar dat de quotes roet in het eten gooien.
Hieronder zal ik laten zien wat ik bedoel.
Dit werkt:
YAML:
1
| "echo -n 'volume 100' | nc -u -w1 192.168.12.34 65432" |
Dit werkt ook:
YAML:
1
| 'echo -n "volume 100" | nc -u -w1 192.168.12.34 65432' |
Wat je ziet is: De string staat tussen quotes zodat het een string is. Omdat ik een andere soort quote (single vs double of andersom) gebruik in de string wordt het gewoon geparsed zonder probleem.
De moeilijkheden beginnen als ik dus een variabele toe wil voegen. Daar zitten dan immers ook quotes in. Of dat nu is in een automation (inherit via een short handle in config) of de volledige string method binnen de string zelf maakt dan niet eens uit.
Dit werkt dus allemaal NIET:
YAML:
1
2
3
4
5
6
7
| "echo -n 'volume {{ (states('input_number.vol_bak').split('.')[0]) }}' | nc -u -w1 192.168.12.34 65432"
"echo -n ''volume {{ (states('input_number.vol_bak').split('.')[0]) }}'' | nc -u -w1 192.168.12.34 65432"
"echo -n \'volume {{ (states('input_number.vol_bak').split('.')[0]) }}\' | nc -u -w1 192.168.12.34 65432"
"echo -n 'volume {{ (states(''input_number.vol_bak'').split(''.'')[0]) }}' | nc -u -w1 192.168.12.34 65432"
"echo -n 'volume {{ (states('input_number.vol_bak').split('.')[0]) }}' | nc -u -w1 192.168.12.34 65432"
"echo -n ""volume {{ (states('input_number.vol_bak').split('.')[0]) }}"" | nc -u -w1 192.168.12.34 65432"
"echo -n \"volume {{ (states('input_number.vol_bak').split('.')[0]) }}\" | nc -u -w1 192.168.12.34 65432" |
et cetera...
Als ik een variabele probeer mee te sturen is dit de debug response waarin het euvel duidelijk te duiden is:
Python:
1
2
| 2020-07-30 21:44:22 DEBUG (MainThread) [homeassistant.components.shell_command] Stdout of command: `echo -n 'volume {{ (states('input_number.vol_bak').split('.')[0]) }}' | nc -u -w1 192.168.12.34 65432`, return code: 0:
b'volume 47 | nc -u -w1 192.168.12.34 65432' |
Ofwel: Je ziet dat er een binary string naar buiten wordt gegooid maar dat de quotes daarbij weggerenderd worden.
Triple quotes om de gehele string dan?
Helaas, dat geeft een foutcode bij validatie:
Python:
1
2
3
4
| Error loading /config/configuration.yaml: while parsing a block mapping
in "/config/configuration.yaml", line 51, column 3
expected <block end>, but found '<scalar>'
in "/config/configuration.yaml", line 57, column 22 |
Om volledig te zijn is de fout die je krijgt met een escape voor de quotes die in de string wél gerenderd moeten worden (dus \'volume {{ bla }}\') als volgt:
Python:
1
2
3
4
| Error loading /config/configuration.yaml: while scanning a double-quoted scalar
in "/config/configuration.yaml", line 57, column 20
found unknown escape character "'"
in "/config/configuration.yaml", line 57, column 30 |
Het vervelende is dus dat er gebruik wordt gemaakt van string formatting in python (f'Hello {thisplanet}') maar het allemaal nét niet volgens standaard python werkt en dus verwarrend is.
En dan denk je: stop dan de quotes in de formatting, wellicht helpt dat?
YAML:
1
| "echo -n {{'\"volume ' + (states('input_number.vol_bak').split('.')[0]) + '\"' }} | nc -u -w1 192.168.12.34 65432" |
Leidt tot
Python:
1
2
| 2020-07-30 22:14:40 DEBUG (MainThread) [homeassistant.components.shell_command] Stdout of command: `echo -n 'volume {{ (states('input_number.vol_bak').split('.')[0]) }}' | nc -u -w1 192.168.12.34 65432`, return code: 0:
b'volume 79 | nc -u -w1 192.168.12.34 65432' |
Voor de volledigheid, met '\'volume {{ bla }} '\'' krijg je de error over duoble quoted scalar weer...
En om echt te dubbelchecken dat een afgeleide var (uit automation) écht niet werkt met al deze trucjes ook nog geprobeerd:
YAML:
1
| "echo -n {{'\"volume ' + vol_data + '\"' }} | nc -u -w1 192.168.12.34 65432" |
En je raadt het al:
Python:
1
2
| 2020-07-30 22:24:17 DEBUG (MainThread) [homeassistant.components.shell_command] Stdout of command: `echo -n {{'"volume ' + vol_data + '"' }} | nc -u -w1 192.168.12.34 65432`, return code: 0:
b'volume 68 | nc -u -w1 192.168.12.34 65432' |
Kan ik anders zelf ergens een simpel stukje python injecteren want, echt, zo moeilijk hoeft dit echt niet te zijn... De hele reden waarom ik HA een kans gaf was wegens python en omdat ik er dus ook vanuit ging dat een UDP versturen niet zo spannend zou zijn (dat is in python echt maar een paar regeltjes code).
Ik zie het even niet meer.