I have installed MSR on a RP5 bare metal and then copied the config and store files. Everything seems to be on the RP5 but I am missing all global expression and I don't see the controller time.
Screenshot 2025-04-06 201446.png
My browser is Microsoft Edge Version 135.0.3179.54 (Official build) (64-bit)
I have probably done something stupid or missed a step but I am stuck.
Thanks for any help.
Hi,
It seems that the widget deletion does not work. I tried to drag the widget to the left (as explained in here https://smarthome.community/topic/1071/deleting-widgets?_=1744037333660)
but it does not delete it. Anyone else experiencing the same problem?
Also the landing page after login is empty and seems be have some JS issues on the dev console:
Screenshot from 2025-04-07 18-06-19.png
fd7f0424-debb-49d3-86d8-9a3b09ad3868-image.png
Using dockerized version of Reactor (Multi-hub) latest-25082-3c348de6 on Chromium 135.0.7049.52 (Official Build) snap (64-bit)
br,
mgvra
Good day all,
I have an notification set up for my washing machine to let me know when it's complete. I have a templete sensor set up in HAAS to let me know if it's Washing, in Standby, or off, based upon the power consumption (Shelly 1PM on outlets)
The MSR code is relatively simple. I have a built in false positive attribute for if MSR gets rebooted, because I would suddenly get tons of notifications when I upgraded MSR.
6774565a-06cc-443f-99c1-e71301b33d83-image.png
What I'm trying to introduce, is a way to verify that I just didn't bump the knob on the washing machine when transferring loads from the washer to the dryer, which turns on the display and brings the power above the Standby threshold.
The power goes up to 3.7W for about 4 minutes if the selector knob is bumped/turned.
What would the best way to do this be? I have most of my MSR code set up for a couple of years now, and my coding logic is struggling a bit.
I think I need a power threshold to be substained for a minimum time period (say 2 or 3 minutes, above 10W), before the other triggers can act. What would the best way to do that be?
Running: latest-25082-3c348de6
Fedora 41 Server
HAAS:
Core
2025.3.4
Supervisor
2025.03.4
Operating System
15.1
Frontend
20250306.0
Build 21228 has been released. Docker images available from DockerHub as usual, and bare-metal packages here.
Home Assistant up to version 2021.8.6 supported; the online version of the manual will now state the current supported versions; Fix an error in OWMWeatherController that could cause it to stop updating; Unify the approach to entity filtering on all hub interface classes (controllers); this works for device entities only; it may be extended to other entities later; Improve error detail in messages for EzloController during auth phase; Add isRuleSet() and isRuleEnabled() functions to expressions extensions; Implement set action for lock and passage capabilities (makes them more easily scriptable in some cases); Fix a place in the UI where 24-hour time was not being displayed.I have the following yaml configuration in local_mqtt_devices file
x_mqtt_device: set_speed: arguments: speed: type: str topic: "command/%friendly_name%" payload: type: json expr: '{ "fan": parameters.speed }'While this works fine, I'm wondering how this could be changed to "fixed" parameters, as in this case "fan" only accepts "A", "Q" or a numeric value of 1-5?
Hi!
I get this message when I'm on the status tab:
System Configuration Check
The time on this system and on the Reactor host are significantly different. This may be due to incorrect system configuration on either or both. Please check the configuration of both systems. The host reports 2025-04-01T15:29:29.252Z; browser reports 2025-04-01T15:29:40.528Z; difference 11.276 seconds.
I have MSR installed as a docker on my Home Assistant Blue / Hardkernel ODROID-N2/N2+. MSR version is latest-25082-3c348de6.
HA versions are:
Core 2025.3.4
Supervisor 2025.03.4
Operating System 15.1
I have restarted HA as well as MSR multiple times. This message didn´t show two weeks ago. Don´t know if it have anything to do with the latest MSR version.
Do anyone know what I can try?
Thanks in advance!
Let's Be Careful Out There (Hill Street reference...) 🙂
/Fanan
I have a very strange situation, where if InfluxDB restarts, other containers may fail when restarting at the same time (under not easy to understand circumstances), and InfluxDB remains unreachable (and these containers crashes). I need to reboot these containers in an exact order, after rebooting InfluxDB.
While I understand what's going on, I need a way to reliable determine that InfluxDB is not reachable and these containers are not reachable, in order to identify this situation and manually check what's going on - and, maybe, in the future, automatically restart them if needed.
So, I was looking at HTTP Request action, but I need to capture the HTTP response code, instead of the response (becase if ping is OK, InfluxDB will reply with a 204), and, potentially, a way to programmatically detect that it's failing to get the response.
While I could write a custom HTTP controller for this or a custom HTTP virtual device, I was wondering if this is somewhat on you roadmap @toggledbits
Thanks!
Hi ,
I'm on
-Reactor (Multi-hub) latest-25067-62e21a2d
-Docker on Synology NAS
-ZWaveJSUI 9.31.0.6c80945
Problem with ZwaveJSUI:
When I try to change color to a bulb RGBWW, it doesn't change to the RGB color and the bulb remains warm or cold white.
I tryed with Zipato RGBW Bulb V2 RGBWE2, Hank Bulb HKZW-RGB01, Aentec 6 A-ZWA002, so seems that it happens with all RGBWW bulb with reactor/zwavejsui.
I'm using from reator the entity action: "rgb_color.set" and "rgb_color.set_rgb".
After I send the reactor command, It changes in zwavejsui the rgb settings but doesn't put the white channel to "0", so the prevalent channel remains warm/cold White and the bulb doesn't change into the rgb color.
This is the status of the bulb in zwavejsui after "rgb_color.set" (235,33,33,) and the bulb is still warmWhite.
x_zwave_values.Color_Switch_currentColor={"warmWhite":204,"coldWhite":0,"red":235,"green":33,"blue":33}The "cold white" and "warm white" settings interfer with the rgb color settings.
Reactor can change bulb colors with rgb_color set — (value, ui8, 0x000000 to 0xffffff) or rgb_color set_rgb — (red, green, blue, all ui1, 0 to 255) but if warm or cold white
are not to "0", zwavejsui doesn't change them and I can't find a way to change into rgb or from rgb back to warm white.
So if I use from reactor: rgb_color set_rgb — (235,33,33) in zwavejsui I have
x_zwave_values.Color_Switch_targetColor={"red":235,"green":33,"blue":33} 14/03/2025, 16:43:57 - value updated Arg 0: └─commandClassName: Color Switch └─commandClass: 51 └─property: targetColor └─endpoint: 0 └─newValue └──red: 235 └──green: 33 └──blue: 33 └─prevValue └──red: 235 └──green: 33 └──blue: 33 └─propertyName: targetColor 14/03/2025, 16:43:57 - value updated Arg 0: └─commandClassName: Color Switch └─commandClass: 51 └─property: currentColor └─endpoint: 0 └─newValue └──warmWhite: 204 └──coldWhite: 0 └──red: 235 └──green: 33 └──blue: 33 └─prevValue └──warmWhite: 204 └──coldWhite: 0 └──red: 235 └──green: 33 └──blue: 33 └─propertyName: currentColorIn zwavejsui, the bulb changes rgb set but warm White remains to "204" and the bulb remais on warm White channel bacause is prevalent on rgb set.
x_zwave_values.Color_Switch_currentColor_0=204 x_zwave_values.Color_Switch_currentColor_1=0 x_zwave_values.Color_Switch_currentColor_2=235 x_zwave_values.Color_Switch_currentColor_3=33 x_zwave_values.Color_Switch_currentColor_4=33Is it possible to targetColor also for "warmWhite" and "coldWhite" and have something similar to this?
x_zwave_values.Color_Switch_targetColor={"warmWhite":0,"coldWhite":0,"red":235,"green":33,"blue":33}Thanks in advance.
Good day all,
I have a reaction set up, that I use for both troubleshooting and changing home modes when one of my family members either arrive or are leaving. I use the companion app for HAAS on our iPhones, and HAAS reports if the person associated with the iPhone enters or leaves the geofenced area around my home. I'm sure most MSR and HAAS users are familiar with this.
I use this rule set mainly as a condition for other rules, however, as part of troubleshooting, a notification is sent through HAAS to the companion app when the rule becomes true. The problem is that I'm getting notifications now for both arriving and departing simultaneously.
96b3f7db-ba09-499e-a78c-86903b603857-image.png
36903cdd-a87f-473b-82ef-af9ef96d3c44-image.png It used to work fine as intended. I'm not sure exactly when it changed, but now I'm getting two notifications when either of these conditions change.
Any idea what could be happening?
Edit:
Running: latest-25082-3c348de6, bare-metal Linux
ZWaveJSControllerr [0.1.25082]
MSR had been running fine, but I decided to follow the message to upgrade to 25067. Since the upgrade, I have received the message "Controller "<name>" (HubitatController hubitat2) could not be loaded at startup. Its ID is not unique." MSR throws the message on every restart. Has anyone else encountered this problem?
I am running MSR on a Raspberry Pi4 connecting to two Hubitat units over an OpenVPN tunnel. One C8 and a C8 Pro. Both are up-to-date. It appears that despite the error message that MSR may be operating properly.
Similarly as for local expressions, global expressions evaluate and update fine when getEntity(...) structure is used. However, at least when certain functions are in use, expressions do not update.
Consider the following test case:
Screenshot 2025-03-13 at 16.29.42.png
Even though auto-evaluation is active, value does not change (it changes only if that expression is manually run). MSR restarts do not help.
Screenshot 2025-03-13 at 16.31.43.png
Note: Tested using build 25067 on Docker. I have also a PR open (but couldn't now get details or PR number as my Mantis account was somehow expired?).
Trying to understand what cause a local expresssion to be evaluated. I have read the manual but I am still not clear about it. Using the test rule below, I can see in the log that the rule is being automatically evaluated every time the temperature entity is changing. That is great...
What I am trying to understand is why the expression is not evaluated based on time as well since the "case" statement has time dependencies.
Any help would be appreciated
I have the following test rule:
eba6a3ea-ff61-4610-88c9-9b9864f11ff8-Screenshot 2025-01-21 095244.png
2d9c1ff5-7b73-4005-b324-9029c2709db9-Screenshot 2025-01-21 095302.png
Here is the expressioncode:
vFrom1 = "09:25:00", vFrom2 = "09:30:00", vFrom3 = "09:41:00", vTo = "10:55:00", # Get current time (format HH:MM:SS) vToDay = strftime("%H:%M:%S"), #Get current house temperature CurrentHouseTemp = getEntity( "hass>Thermostat2 " ).attributes.temperature_sensor.value, case when CurrentHouseTemp <= 19 and vToDay >= vFrom1 && vToDay <= vTo: "true1" # From1 when CurrentHouseTemp <= 20 and vToDay >= vFrom2 && vToDay <= vTo: "true2" # From2 when CurrentHouseTemp < 26 and vToDay >= vFrom3 && vToDay <= vTo: "true3" # From3 else "false" endI am getting a Runtime error on different browsers when I click exit when editing an existing or creating a new global reaction containing a group. If the global reaction does not have a group I don't get an error. I see a similar post on the forum about a Runtime Error when creating reactions but started a new thread as that appears to be solved.
The Runtime Error is different in the two browsers
Safari v18.3
Google Chrome 133.0.6943.142
TypeError: self.editor.isModified is not a function at HTMLButtonElement.<anonymous> (http://192.168.10.21:8111/reactor/en-US/lib/js/reaction-list.js:171:34) You may report this error, but do not screen shot it. Copy-paste the complete text. Remember to include a description of the operation you were performing in as much detail as possible. Report using the Reactor Bug Tracker (in your left navigation) or at the SmartHome Community.Steps to reproduce:
Click the pencil to edit a global reaction with a group.
Click the Exit button.
Runtime error appears.
or
Click Create Reaction
Click Add Action
Select Group
Add Condition such as Entity Attribute.
Add an Action.
Click Save
Click Exit
Runtime error appears.
I don’t know how long the error has been there as I haven’t edited the global reaction in a long time.
Reactor (Multi-hub) latest-25060-f32eaa46
Docker
Mac OS: 15.3.1
Thanks
I am trying to delete a global expression (gLightDelay) but for some strange reason, it comes back despite clicking the Delete this expression and Save Changes buttons.
I have not created a global expression for some times and just noticed this while doing some clean-up.
I have upgraded Reactor to 25067 from 25060 and the behaviour is still there. I have restarted Reactor (as well as restarting its container) and cleared the browser's cache several times without success.
Here's what the log shows.
[latest-25067]2025-03-08T23:50:22.690Z <wsapi:INFO> [WSAPI]wsapi#1 rpc_echo [Object]{ "comment": "UI activity" } [latest-25067]2025-03-08T23:50:26.254Z <GlobalExpression:NOTICE> Deleting global expression gLightDelay [latest-25067]2025-03-08T23:50:27.887Z <wsapi:INFO> [WSAPI]wsapi#1 rpc_echo [Object]{ "comment": "UI activity" }Reactor latest-25067-62e21a2d
Docker on Synology NAS
Morning, experts. Hard on learning about the internet check script in MSR tools, I was wondering what suggestions anyone has about a local (i.e. non-internet dependent) notification method.
This was prompted by yesterday's fun and games with my ISP.
I've got the script Cronned and working properly but short of flashing a light on and off, I'm struggling to think of a way of alerting me (ideally to my phone)
I guess I could set up a Discord server at home, but that feels like overkill for a rare occasion. Any other suggestions?
TIA
C
Hi,
I'm trying to integrate the sonos-mqtt (https://sonos2mqtt.svrooij.io/) with the MSR and it's coming along nicely so far.
But cannot wrap my head around how to define custom capabilities in MQTT templates. I need this for the TTS announcements and similarly for the notification sounds where I would pass the sound file as parameter.
So this is what I have in the local_mqtt_devices.yaml
capabilities: x_sonos_announcement: attributes: actions: speak: arguments: text: type: string volume: type: int delay: type: intAnd this is the template:
templates: sonos-announcement: capabilities: - x_sonos_announcement actions: x_sonos_announcement: speak: topic: "sonos/cmd/speak" payload: expr: > { "text": parameters.text, "volume": parameters.volume, "delayMs": parameters.delay, "onlyWhenPlaying": false, "engine": "neural" } type: jsonSo the speak action should send something like this to topic sonos/cmd/speak
{ "text": "message goes here", "volume": 50, "delayMs": 100, "onlyWhenPlaying": false, "engine": "neural" }At startup the MSR seems to be quite unhappy with my configuration:
reactor | [latest-25016]2025-02-09T08:19:59.029Z <MQTTController:WARN> MQTTController#mqtt entity Entity#mqtt>sonos-announcement unable to configure capabilities [Array][ "x_sonos_announcement" ] reactor | i18n: missing fi-FI language string: Configuration for {0:q} is incomplete because the following requested capabilities are undefined: {1} reactor | i18n: missing fi-FI language string: Configuration for {0:q} has unrecognized capability {1:q} in actions reactor | Trace: Configuration for {0:q} is incomplete because the following requested capabilities are undefined: {1} reactor | at _T (/opt/reactor/server/lib/i18n.js:611:28) reactor | at AlertManager.addAlert (/opt/reactor/server/lib/AlertManager.js:125:25) reactor | at MQTTController.sendWarning (/opt/reactor/server/lib/Controller.js:627:30) reactor | at MQTTController.start (/var/reactor/ext/MQTTController/MQTTController.js:268:26) reactor | at async Promise.allSettled (index 0) Configuration for "sonos-announcement" has unrecognized capability "x_sonos_announcement" in actions Controller: MQTTController#mqtt Last 10:21:37 AM Configuration for "sonos-announcement" is incomplete because the following requested capabilities are undefined: x_sonos_announcement Controller: MQTTController#mqtt Last 10:21:37 AMThis is probably a pretty stupid question and the approach may not even work at all, but maybe someone or @toggledbits for sure, could point me to the right direction.
Basically the idea is to be able to send TTS messages from reactions using entity actions. I've previously used HTTP requests to Sonos HTTP API (https://hub.docker.com/r/chrisns/docker-node-sonos-http-api/) for the same functionality, but since moving to sonos-mqtt, I need a way to send the TTS notifications using MQTTController. Along with the actual message, volume and delay must also be parameterizable.
br,
mgvra
MSR latest-25016-d47fea38 / MQTTController [0.2.24293]
Hi, @toggledbits
I just noticed that following a reboot of my raspberry pi, some of the rules, that I was expecting to recover, are not catching up following a reboot. I have made a simple test rule (rule-m6rz6ol1) with only "after Date/time" as trigger and "turn on a lamp" as a set reaction. All my infrastructure is on the same board so Reactor, Hass, Zwavejs, ... are all rebooting.
Here is the sequence of the test case (All time converted to Zulu to match logs):
Rule "after Date/Time" set to 14:05:00z Shutdown on Raspberry Pi at 14:04:00z Power back up at 14:08:00z Rule overview shows true as of 14:08:14z waiting for 00:00:00 in GUIFrom the log I can see that MSR is picking up the rule and knows that the state of the rule has changed from false to true and tries to send the update to HASS but failed with websocket error.
Here is what I see from the log:
14:04:04z shutdown complete 14:08:08z Power up 14:08:13.111z websocket connection 14:08:15:323z Reaction to the light failed, Websocket not opened After there is a series of websocket connection attempt until 14:08:51z where it seemed to be really ready.Back in 2021 we had a discussion (https://smarthome.community/topic/700/solved-start-up?_=1738766986566) and you proposed to add a startup_delay:xxxx and startup_wait:xxxx parameter in the engine section of "reactor.yaml". When I try the startup_delay (this used to be a hard delay), the engine failed to start (I think). I then try the startup_wait:xxxx without any success. Since it wait for the connection status to be up to cancel the delay, it does not do anyting since Hass is reporting the socket up without really being up ( I think...).
Questions:
Did I figured it all wrong? should the startup_delay:xxxxx have worked? Any ideas?Here is the log:
OK now I am stuck. I did add the log but when I submit the editor complained saying that I am limited to 32767 characters. The log from the shutdown to the time the websocket is stable is about 300000 character long. What are my options?
Not a big issue simply a request if easily doable.
The MSR logs files inside the container are owned by root witch is fine however, the permissions are very restrictive. I do not know if there is something wrong with my installation but the logs permission are set to 222 (write only). Even if the docker volume is set for Read/Write the log files are retaining these values.
I go around the problem by doing a chmod 777 on all reactor logs but every time there is an MSR log rotation the permissions are set back to 222. So unless the permission are implemented in the container there is no permanent solution to this (that I know of).
I do not know much about Docker container so I do not know what is involved here.
Can the logfiles permission be simply chaged in the container to at least allow "other" read permission?
Could the MSR log rotation routine implement a chmod to set the permission?
Just a small anoyance
Thanks
@toggledbits In the MSR documentation, under Standard Capabilities, I noticed that the
button.since attribute was deprecated as of version 22256 and the metadata is the preferred way to access the last-modified time of an attribute.
Am I reading this right? Should I stop using it in my rules?
Thanks
[Reactor] Services with sync response
-
Hi @toggledbits
I'm working on a controller to generate llm response from a prompt in reactor. I have http response coming thru an http request action at the moment, capturing the response inside a local variable. So, it's practically sync.
I want to create a controller, so I don't have to rely on a proxy (and have a simpler architecture), and duplicate absurd http actions, but AFAIK in the current implementation, actions are async only. But if I have multiple requests going on, I cannot be sure what it's really inside an attribute. I also thought that something like a correlation id when sending the request could be used to identity multiple responses, but I wanted to double check with you before starting with something too complicated. I also noticed that some actions in home assistant (ie forecast) are sync and I'm wondering if you have any plan or hint to address this situation. Thanks.
Thanks.
-
@therealdb said in [Reactor] Services with sync response:
I want to create a controller, so I don't have to rely on a proxy (and have a simpler architecture), and duplicate absurd http actions, but AFAIK in the current implementation, actions are async only. But if I have multiple requests going on, I cannot be sure what it's really inside an attribute.
Sorry, I'm not really clear on what you're asking here. When you say "actions are async only", in what context are you referring to? Do you mean an action running in a Reaction, or do you mean the implementation of an action in a Controller instance?
-
sorry, I was on my phone. I was referring to the fact it's impossible to get the response from a service inside a reaction. so, let's says I need to do that in order to pass a prompt and generate a response:
HTTP action is able to capture the reply in a variable. I want to build a custom controller with an action that could do the same, so reply in line with an output that I could capture inside a local variable (because replicating this code multiple times is not really efficient nor smart). Is that clear now?
-
Got it. Let me back up a second and supply a bit of background.
When a Reaction is asked to perform an action on an entity, the Engine's executive calls
Entity.perform()
on the target entity with the requested action name and parameters. By default, the entity will then call its Controller'sperformOnEntity()
with itself, the action name, and the action's parameters. The Controller is expected to provide whatever implementation is necessasry to cause the target object represented by the entity to perform the desired action. TheperformOnEntity()
implementation is expected to return a Promise that resolves when the command has been issued successfully (or, when the command complete successfully, if that is something that can be determined). That Promise is passed back as the call stack unwinds until the Engine gets it. At that point, the Engine will suspend execution of the Reaction until the action Promise is fulfilled (successfully or not).TL;DR: The Engine waits for a Controller to signal that an action in a Reaction has been requested (or completed) before moving on to the next action.
I think this is useful for you. Your implementation of the action must return a Promise that must resolve before the Engine moves on. So your action can launch its HTTP request (e.g. using
Controller.fetchJSON()
or.fetchText()
), which itself is an asynchronous operation, and wait for that response, then do whatever processing it needs to on that response, store the result wherever it needs to go, and then and only then resolve the original Promise. The Engine will be waiting that entire time before moving on to the next action in the running Reaction.A couple more things to know:
- If you don't supply an override of
performOnEntity()
in your Controller implementation, the default (Controller base class) implementation will try to call a method calledaction_<capability>_<actionname>
. For example, your Controller could implement the actionx_mycontroller.update_weather
by providing a methodaction_myController_update_weather( entity, parameters )
(whereentity
is the target andparameters
is an object of key/value pairs). - If you decide to implement an override of
performOnEntity()
, make sure it callssuper.performOnEntity()
if it can't figure out what to do (i.e. it is asked to perform an action it doesn't understand).
Hopefully I've answered your question and maybe provided some additional information that will help.
- If you don't supply an override of
-
Ok, that's clear and I think I've already done that in a coupe of controllers.
What I'm saying here is that I need to do something similar to be sure that I could capture the response and be sure I'm not getting another one. I want to capture the output in a variable like HTTP actions, but using an entity action.AFAIK I cannot do that in a reliable way.
-
I want to capture the output in a variable like HTTP actions
If you're building a Controller, it would (IMO) make more sense to store the query result on an entity (even if it's the system entity for the Controller) in an attribute rather than a global variable.
AFAIK I cannot do that in a reliable way.
I'm not really sure where you are going with the "capture the response and be sure I'm not getting another one". If you are using any of the fetch methods, for example, the response would be handled on the Promise that was created:
this.fetchJSON( "http://example.com/myquery" ).then( jsondata => { // The data from the response is now in `jsondata`. It will contain // only the data for this query, no other. this.getSystemEntity().setAttribute( 'x_mycontroller.myquery_result', jsondata ); });
There are many existing Controllers that can submit multiple commands to a hub/service and handle a truly asynchronous response (e.g. via a callback or a later message on the channel). In these instances, a unique (for the session) ID is passed as part of the request, and the hub's API returns the ID as part of its response, so we know what the hub is responding to. Both HassController and ZWaveJSController do this, for example.
Here's what that looks like for both of these Controllers. This method is used to send a request to the hub. It assigns a serial ID as part of its work:
/** Returns a Promise that sends a request to ZWave JS and resolves when it gets * the matching reply. The reply can time out, and the Promise rejects. */ _send_tracked_message( req, timeout ) { const self = this; timeout = timeout || DEFAULT_TASK_TIMEOUT; let slot = { req_id: ++this.next_msg_id, expires: Date.now() + timeout, resolve: false, reject: false, req: req }; slot.promise = new util.TimedPromise( (resolve,reject) => { // Now that we're in the Promise, save the resolvers for later use when we get the response. slot.resolve = resolve; slot.reject = reject; req.messageId = slot.req_id; self.log.debug( 5, "%1 sending #%2: %3", this, slot.req_id, req ); self.ws_send( JSON.stringify( req ) ); }, timeout ).catch( err => { self.log.err("%1 request %2 (%4) failed: %3\n%5", self, slot.req_id, err, slot.type, slot.req); slot.reject( err ); delete self.pending[String(slot.req_id)]; }); this.pending[String(slot.req_id)] = slot; return slot.promise; }
The Controller has an instance variable (an object) called
pending
that keeps track of all pending requests; it's created empty ({}
) in the Controller's constructor and when a connection to the hub is acquired. Likewise, thenext_msg_id
variable is initialized to 0 in the constructor. The method creates a slot, which is just an object with enough data to track the request, using aTimedPromise
(inutil
library) so that we can have a timeout if the hub never answers. The slot is stored inthis.pending
so we can get back to it later, whenever/however the response arrives.The hub later sends a response somehow. In Z-Wave JS that's a
result
type message on the WebSocket channel, and the handler looks like this:/** Called for "result" type messages. If associated with a tracked request, that Promise will * resolve or reject based on the returned success flag. Otherwise, the message is logged (if * level is high enough) and the message discarded. */ _handle_result( event ) { this.log.debug( 9, "%1 full result reply %2", this, event ); // Find the slot in pending let slot = this.pending[String(event.messageId)]; if ( slot ) { delete this.pending[String(event.messageId)]; if ( event.success ) { this.log.debug( 5, "%1 request %2 (%3) success notification", this, slot.req_id, slot.req.command); slot.resolve( event ); } else { // Ref: https://github.com/zwave-js/zwave-js-server#errors this.log.debug( 5, "%1 command result error: %2", this, event ); let err; if ( "zwave_error" === event.errorCode ) { err = new Error( `Z-Wave error ${event.zwaveErrorCode}: ${event.zwaveErrorMessage}` ); } else { err = new Error( event.errorCode ); } slot.reject( err ); } } else { this.log.debug( 6, "%1 can't resolve request %2 in reply, slot not found, maybe already timed out", this, event.messageId ); } }
In this case, the slot data is acquired from
this.pending
. The slot is removed fromthis.pending
, and then the storedresolve()
function is called (with the result message data) if the hub indicates success, orreject()
is called (with the error data) otherwise.Does this help?
-
that's fair, but I think the problem is different. My flow is this one:
Prompt => OpenAI => response
It's not really different from what HTTP action is doing, after all.
Prompt is by definition dynamic, so I cannot "bind" it to an entity. I think having multiple entities just because I need multiple response is cumbersome (and, probably, not efficient). It will eventually lead to confusion and complicate the final setup, because every time I need to write a new prompt, a new entity will be needed as well.Now, if I create multiple entities, your remarks are obviously right. I did a couple of controllers and the infrastructure is pretty clear to me. But if I want to create just the system entity, with an action like
x_ai.prompt
, I cannot store the response inside an entity attribute, because I could potentially run multiplex_ai.prompt
requests and this could cause a lot of troubles. I understand that in a entity-first world this is an edge case, and in fact this is more a service-oriented Controller than the traditional ones, but nevertheless I thinks this use case will eventually surface more and more. It's like theperform_action
returning an object as result using the Promise, instead of just being void.In my comment, I was referring to a local variable. Imagine a prompt giving you a number as a result, because you're using the GenAI engine to make some prediction based on your logic. By capturing this value inside a variable, I could write, inside the same rule, the logic necessary to tie this value to some specific actions, like turning on some light, or send a notification if a threshold is met. I know I can assign it to the system entity, but this will need multiple rules to capture the result, so this will probably make things very complicated.
I'm asking for some guidance in order to implement this kind of architecture, where the response is directly tied (and captured, and used) in the same context of the rule where the request is generated. I'm not sure if this is clearer than my previous attempt to describe the question. Thanks!
-
What causes the request? Local variables live in rules, but rules are only evaluated (and local variables updated) when a dependency notifies a change. What will cause the query to the remote endpoint?
-
It could be a door being opened, a time trigger - or something else. The prompt will be generated from a source (this could be some text coming from an e-mail, a web site, or status coming from sensors - sky's the limit), sent to the OpenAI (or something else), processed, and a response generated. The output could be a JSON, a string, or whatever you want. The GenAI model is capable of generating everything, based on the prompt. This is a basic example:
The prompt is composed inline, and the response is being generated (and, in this case, sent to Alexa for TTS).
Here's another variation, for a JSON payload:
It's crucial to send the request and get the response in the same logic, otherwise it will be impossible to easily build something with this. Thanks.
-
OK. Still not fully there for me. When you run the HTTP Request action, it waits for the response, and then stores the response in the specified local variable. That value is now available to the remainder of the Reaction, so you can send it to TTS.
What am I missing?
-
I don't want to use an HTTP action, but a controller one! Right now it's impossible to save entity action response to a variable, if I'm not missing something. The question is this: how to build the same flow using a controller action?
-
But you can use the entity-based action response as if it was a variable. It is in many ways better, in fact, because there's a ton more code required in Reactor to make rule conditions responsive to variables than there is to make it responsive to attributes — attributes are very efficient.
I know you don't want to use an HTTP Request, but I want to know why. I guess I'm not understanding what's inadequate about the HTTP Request for your purpose in the first place.
-
My /ai/prompt endpoint encapsulate the logic to query OpenAI. That's great for me personally (so, not really shareable with the community), but that's another moving part in the system that could potentially fail. This is a simple web API that is proxying OpenAI (in this case Azure Open AI, but that's the same). It is acting as my controller, but it's not reusable, it's prone to errors and I think an
OpenAIController
will be better than this.All that said:
But you can use the entity-based action response as if it was a variable. It is in many ways better, in fact, because there's a ton more code required in Reactor to make rule conditions responsive to variables than there is to make it responsive to attributes — attributes are very efficient.
So, you think that it's better to have two rules, one triggering the request and another looking for the response and watching the attributes (ie: response and response_id, tied to a request_id from the original prompt)?
-
I'm not understanding why you think it takes two rules.
If you run an HTTP Request and store the response in a local variable, the next step in the same Reaction has access to that local variable. And the contents of that local variable will be exactly the response to the request, not any other request (so no ID tracking is necessary). The Rule that triggers the request can be the same rule that processes it.
Are you assuming that the HTTP Request action is asynchronous when storing the result? Because it's not. It will wait for the result and store it before moving on to the next step of the Reaction. That's documented.
-
-
@therealdb said in [Reactor] Services with sync response:
No, I'm quite experienced and I know how a promise works
I'm not talking about a Promise, and of course I know well that you know how that works. I'm talking about the HTTP Request action in a Reaction. It waits for the response and stores it, so that the rest of the steps of the Reaction can work with the response received. If that doesn't address your need, I'm unclear how.
-
ok, so, here's a photoshopped version of the ideal world I'm trying to describe:
The point here is that I don't want to do an HTTP request, I want to call an entity action and capture the result, if any, in a variable. Keep in mind that I'm describing an ideal world, and I'm OK to alternative solutions that still uses a Controller (and not an HTTP Action, that's temporary and I want to move to a custom Controller), wait for a response from a service, capture it and use in the same flow, if possible.
So, more like services than entity-oriented controller.
I hope this is better explained now. Thanks!
-
OK. I think I see where you are going. I was bogged down by the HTTP part, since that's existing functionality you can solve the problem with today. You're really asking for something much bigger. You just generally want entity actions to be able to return data, which they currently don't, so you can do things like:
- Return the next upcoming event from a calendar;
- Receive a value and look it up in a table, then return the found result;
- Given the name of a playlist on a media player, return the list of media it contains.
- Given the symbol for a security or crypto coin, return its current price.
- Run a script on Home Assistant and receive whatever response it returned.
And you want this to work in-line in Reactions, without necessarily binding the result value to an attribute on the entity performing the action, or having to preconfigure an input in YAML config (e.g. the symbol for a stock or crypto asset to be fetched/polled). The result value is, in fact, typically temporary and not useful outside the context of the Reaction (although it and values derived from it can be stored otherwise by other steps of the Reaction).
Do I have it now?
-
@toggledbits yes sir. That why you're the master and I'm your humble follower
Because I know it's not trivial, I'm also asking for guidance on how to achieve something similar with what we have today. Thanks.
-
I'm on it. Sit tight.
-
T toggledbits locked this topic on
-
T toggledbits unlocked this topic
-
T toggledbits locked this topic