I have downloaded the system and everything and I have two problems mainly to see if you can lend me a hand.
First of all I would like to say that I’m triying to use my own python script after de system recognise of the different commands. I have changed the profile as appears in the official documentation but nothing happens when I say one command. What could be happening? How can I see where is the problem?
On the other hand, someone knows why Porcupine don’t works now?
I haven’t tested this version for a while, so I can’t help you with that.
As for the Python script: are you using MQTT/Hermes in your script or do you run it as a local intent handler script? You are sure that Rhasspy detects the intents your script has to react to?
About Porcupine now I´m using Snowboy, so is no important problem.
My idea is that after having a command recognized by Rhasspy a python program is run that works based on the input json to be able to make certain requests later with POST.
What I have done has been to configure the profile as indicated in Documentation but nothing happens when it detects the different commands (which detects them correctly already displayed in the LOG tab)
If I execute the command as you indicate, I don’t see any errors or anything strange.
I enclose the code below, it is a very simple code since it is an initial test:
#!/usr/bin/env python
import sys
import json
import random
import datetime
import io
import requests
import socket
from adapt.intent import IntentBuilder
def speech(text):
global o
o["speech"] = {"text": text}
# get json from stdin and load into python dict
o = json.loads(sys.stdin.read())
intent = o["intent"]["name"]
msg = o["text"]
if intent == "GetTime":
now = datetime.datetime.now()
speech("It's %s %d %s." % (now.strftime('%H'), now.minute, now.strftime('%p')))
elif intent == "Hello":
replies = ['Hi!', 'Hello!', 'Hey there!', 'Greetings.']
speech(random.choice(replies))
elif intent == "PercentageControl":
percentage_control(self,msg)
replies = ['Okey', 'Done!', 'Adjusted as your like']
speech(random.choice(replies))
elif intent == "ChangeState":
things_onoff(self,msg)
replies = ['Okey', 'Done!', 'Adjusted as your like']
speech(random.choice(replies))
# convert dict to json and print to stdout
print(json.dumps(o))
def send_post_openhab(self,item, signal):
URL= 'http://10.5.55.3:8080/rest/items/'+item
headers = {
'Content-Type': 'text/plain',
'Accept': 'application/json',
}
data = signal
url_archivo_salida = 'response.xml'
try:
resp = requests.post( URL, headers = headers, data = data )
except Exception as e:
print( 'The exception >> ' + type(e).__name__ )
raise e
else:
#requests.codes.ok = 200 => OK
if( resp.status_code == requests.codes.ok ):
with open( url_archivo_salida, 'w' ) as f:
f.write( resp.text )
f.close()
else:
out = 'resp.status_code >> ' + str(resp.status_code) + ' != ' + str(requests.codes.ok)
def percentage_control(self,msg):
utterance = msg.data["utterance"]
number = str(extract_number(utterance))
if "lights" in msg.data.get('utterance') or "light" in msg.data.get('utterance'):
if "kitchen" in msg.data.get('utterance'):
if "to" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen_Dimmer", number)
if "living room" in msg.data.get('utterance'):
if "to" in msg.data.get('utterance'):
self.send_post_openhab("LR_Dimmer", number)
if "blinds" in msg.data.get('utterance'):
if "kitchen" in msg.data.get('utterance'):
if "up" in msg.data.get('utterance') or "raise" in msg.data.get('utterance') :
self.send_post_openhab("Blind1", "0")
self.send_post_openhab("Blind2", "0")
if "down" in msg.data.get('utterance') or "lower" in msg.data.get('utterance'):
self.send_post_openhab("Blind1", "100")
self.send_post_openhab("Blind2", "100")
elif "to" in msg.data.get('utterance'):
self.send_post_openhab("Blind1", number)
self.send_post_openhab("Blind2", number)
self.send_post_openhab("Blind3", number)
def things_onoff(self,msg):
print (msg.data.get('utterance'))
if "lights" in msg.data.get('utterance') or "light" in msg.data.get('utterance'):
if "kitchen" in msg.data.get('utterance'):
if "table" in msg.data.get('utterance'):
if "on" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen1", "ON")
if "off" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen1", "OFF")
elif "work" in msg.data.get('utterance'):
if "on" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen2", "ON")
if "off" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen2", "OFF")
else:
if "on" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen_Dimmer", "100")
if "off" in msg.data.get('utterance'):
self.send_post_openhab("Kitchen_Dimmer", "0")
def stop(self):
pass
I would suggest to start with something much more simple, such as this one. If this works, you know the error is in your script and not in Rhasspy’s intent handling.
The first step to solve this issue is figuring out exactly what is going wrong. Define a json inside your script that has the same format as the one you expect to be handled and run your script manually from the console. Also check if the answer looks like it should. If your script manually the next step is figuring out if it is called from rhasspy at all. To do that you could write into log file from your python script and then check if there is an entry.
Nor does anything happen if I put that code as indicated in the path of the profile.json. It is as if the corresponding program will not be executed because nothing happens.
In addition I get the following problem: “HomeAssistantIntentHandler Can’t contact server” I understand that it appears to me by the configuration of the command as such, although I do not want to use Haas
The initial problem I think is that the Python program does not run as such after detecting a command since nothing happens or testing with the example they have told me. I don’t know what I can do to make it really run or what I’m doing wrong
On the other hand, I’m sorry for not knowing how it is, but can you be more explanatory to me as it would be to check if my code works as such? How could I execute the code by seeing how it takes the json data in the program from the previous message?
Basically your script is a python script and you can run it with the normal console instead of with rhasspy. If it is not called by rhasspy then it needs to get the json data from somewhere so you need to put that into your skript and then run it. If your skript outputs a valid json (and it should if it works) then we know that there is no error in the skript itself preventing it from running and that the skript can run. That rules out a few possibilities of why it doesn’t work
So basically figure out how to define a json in python, put it in your o variable instead of reading stdin
It is a good idea to check where the error is, I just did it and the program runs without any problem so that the problem I understand is how to configure rhasspy to run the program when a command is detected. I have made the configuration of the profile as indicated so that I do not know where the error may be.
Now the next step is to add a log entry or something to your skript. That way something in your file system changes when the program is run. Test the logging with a manual start and if your log works try it with rhasspy and you will know if your skript is called from rhasspy. If it is then rhasspy either doesn’t give you data the way you expect it or you don’t give data back the way rhasspy expects it. If it doesn’t run then you know rhasspy has some problem executing the script.
I have added to the program that a txt file is created every time the code is executed, if I execute it manually if it is created. So the script is not running. What I have done has been to add to the profile.json the lines indicated in the documentation. Perhaps it is not the correct way to do it, or do I have to do something else or different for the program to run after detecting a command?
Only thing I can think of is to check the path. The documentation gives you a few variables to specify the path to your script, did you use them? If not, try using one to create the path because that might be throwing it off. If you are using docker the path that you use on the console will not be the same as the one rhasspy needs because docker is something like a different system when run.
That if I didn’t know, if I am using a docker and I have set the normal path that appears when pwd when the file appears. How should I do being a docker?
$RHASSPY_BASE_DIR - path to the directory where Rhasspy is running from
$RHASSPY_PROFILE - name of the current profile (e.g., “en”)
$RHASSPY_PROFILE_DIR - directory of the current profile (where profile.json is)
That is in the documentation. So you pick one of those you want to use, I personally would go with the $RHASSPY_BASE_DIR. Then you make sure that your script is somewhere in that base dir. I would make a folder there called scripts or so and then put the script there. Then the path for your script would be $RHASSPY_BASE_DIR/scripts/my_script.py.
Then your rhasspy will resolve $RHASSPY_BASE_DIR to the directory where it is running from and then find the file.
It still does not work, I believe that the fault is in the profile.json or that I am leaving something to do. The profile.json that I am using is the following:
I do not have a running rhasspy to test stuff on so I am just going by the documentation. The “handle” part there has two lines more than yours and at least one of them looks like it is needed for it to work.
Resurrecting an old post since I am having a similar issue.
I created my own python script for a handler, and it works from container terminal, but doesn’t seem to be called from Rhasspy.
So - I copied the example handler.py to the profile/en directory, created intents to match it, and still nothing… can someone help me debug this? I’m not sure where to find any errors (the log in the GUI shows nothing useful).
I tried adding the arguments and forward_to_hass flags and those didn’t seem to have any effect.
handler.py
#!/usr/bin/env python
import sys
import json
import random
import datetime
def speech(text):
global o
o["speech"] = {"text": text}
# get json from stdin and load into python dict
o = json.loads(sys.stdin.read())
intent = o["intent"]["name"]
if intent == "GetTime":
now = datetime.datetime.now()
speech("It's %s %d %s." % (now.strftime('%H'), now.minute, now.strftime('%p')))
elif intent == "Hello":
replies = ['Hi!', 'Hello!', 'Hey there!', 'Greetings.']
speech(random.choice(replies))
# convert dict to json and print to stdout
print(json.dumps(o))
sentences.ini
[GetTime]
What time is it
[Hello]
Hello
Can anyone spot what I am missing or doing wrong?
Currently on Rhasspy version 2.5.5
Last time I tested in 2.5 after it came out I noticed that the script isn’t called. I opened an issue and kept an eye on the development and I don’t think it is fixed yet. Try the rhasspy-hermes-app or another mqtt library to get it working, that is the preferred way for 2.5 right now.
Created the script copy and pasting in the time_app.py, set the intent handler to the new file (making sure it was executable). GetTime was already a sentence, so no change there.
Still not working…
I’m sure I’m missing something stupidly simple… but I can’t figure it out.
I was digging in the code trying to understand something, and I think I found something but don’t know if it would cause a problem…
In the intent handler, there is a reference to satellites… but at least in the GUI there is no way to set them… I wasn’t sure if this would cause it to error when trying to use a local intent handler.
# Intent Handling
handle_system = profile.get("handle.system", "dummy")
if handle_system not in {"dummy", "hermes"}:
satellite_site_ids = str(profile.get("handle.satellite_site_ids", "")).split(
","
)
Since I’m pretty dev dumb… would this cause an error if the value doesn’t exist and doesn’t have a fallback default? Going to post this on your issue to help track it.
I haven’t seen you mention MQTT, but Rhasspy Hermes App is meant to be used with an MQTT broker, as the Hermes protocol is defined as MQTT messages. Have a look at the arguments such as --host to define the address of the MQTT broker in the usage documentation.
I’m probably just using it wrong. At first I was trying to use it as an intent handler (setup in the GUI). Then I ran it just in terminal realizing that it was probably stand alone.
I was running it within the container. It says in the usage docs that it uses localhost and 1883. I changed the port to 12183 since that’s what the internal MQTT uses. I didn’t change the address since it should be localhost, but I have had issues with that in containers in the past, so I will try using the container IP and see if that fixes it.
With Rhasspy Hermes App you don’t have to configure your app as an intent handler in Rhasspy’s web interface, it works completely independently from Rhasspy. It works even when there’s no intent handler defined in Rhasspy because it’s using MQTT.
Yes I did… looks like localhost worked fine - starts up and connects.
I did a sentence recognition from the GUI and that appears to be caught too…
So it looks like the speech isn’t getting back into Rhasspy.
So to run a hermes-app do you need to set it up as a service? It has to be running all the time I assume. Right now I just have a terminal running it, but of course it dies when I close.
Ah crap… I just realized I changed to a different example file and it uses the EndSession for the return… I’m going to go out on a limb and guess that doesn’t initiate speech like the speech command does. I’ll try changing to the other example file.
Ok, so the session is ended, this means that Rhasspy should have received this message over MQTT and should have activated the TTS. If you don’t hear anything, there’s something wrong with the TTS. Or does the TTS work otherwise?
Yes you have to run a Rhasspy Hermes App as a service. This could be in a systemd service or in another Docker container. An easy way to create this service is on the roadmap, but for now you’ll have to do it manually.
"""Example app to react to an intent to tell you the time."""
import logging
from datetime import datetime
from rhasspyhermes.nlu import NluIntent
from rhasspyhermes_app import EndSession, HermesApp
_LOGGER = logging.getLogger("TimeApp")
app = HermesApp("TimeApp")
@app.on_intent("GetTime")
async def get_time(intent: NluIntent):
"""Tell the time."""
now = datetime.now().strftime("%H %M")
return EndSession(f"It's {now}")
app.run()
In the connection line, it does have CERT_REQUIRED… but I don’t have any certs setup for Rhasspy since its all internal… would this cause a problem? I would expect it not to connect if that were the case…
Never mind - I added --tls-cert-reqs CERT_NONE and it didn’t fix it.
OKAY - I was able to install the mosquitto-client on the container, and subscript to the topics.
After doing recognition in Rhasspy, the hermes-app works, and does appear to post back to the correct topic:
Okay - found this error in the docker log, seems relavent:
[ERROR:2020-08-04 17:10:43,442] asyncio: Task exception was never retrieved
future: <Task finished coro=<HermesClient.publish_all() done, defined at /usr/lib/rhasspy/rhasspy-hermes/rhasspyhermes/client.py:368> exception=AssertionError('No session')>
Traceback (most recent call last):
File "/usr/lib/rhasspy/rhasspy-hermes/rhasspyhermes/client.py", line 370, in publish_all
async for maybe_message in async_generator:
File "/usr/lib/rhasspy/rhasspy-dialogue-hermes/rhasspydialogue_hermes/__init__.py", line 668, in on_message
async for end_result in self.handle_end(message):
File "/usr/lib/rhasspy/rhasspy-dialogue-hermes/rhasspydialogue_hermes/__init__.py", line 375, in handle_end
assert self.session is not None, "No session"
AssertionError: No session
Nice bonus, this actually helped me fix the other issue with the local command handler. Looks like it isn’t working with the ${RHASSPY_PROFILE_DIR} - using an absolute path seems to fix it.
Anyway, back to the hermes-app - something is wrong with the sessions I see… not sure how to dig deeper yet… will keep looking.