gazoscalvertos / Hass-Custom-Alarm

Yet another take on a home assistant custom alarm
221 stars 94 forks source link

MQTT ARM_AWAY does not work #49

Open danobot opened 6 years ago

danobot commented 6 years ago

Hi, I am on HA v0.81.0 and bwalarm v1.0.4.

When sending an MQTT message to arm the alarm, I am getting this error in the logs:

2018-10-29 10:45:14 ERROR (MainThread) [homeassistant.core] Error doing job: Exception in callback <bound method MQTT._mqtt_handle_message of <homeassistant.components.mqtt.MQTT object at 0x7fd5e41695f8>>
Traceback (most recent call last):
  File "uvloop/cbhandles.pyx", line 66, in uvloop.loop.Handle._run
  File "/usr/src/app/homeassistant/components/mqtt/__init__.py", line 775, in _mqtt_handle_message
    subscription.callback, msg.topic, payload, msg.qos)
  File "/usr/src/app/homeassistant/core.py", line 327, in async_run_job
    target(*args)
  File "/config/custom_components/alarm_control_panel/bwalarm.py", line 668, in message_received
    self.alarm_arm_away('')
  File "/config/custom_components/alarm_control_panel/bwalarm.py", line 485, in alarm_arm_away
    self.process_event(Events.ArmAway)
  File "/config/custom_components/alarm_control_panel/bwalarm.py", line 577, in process_event
    self._hass.services.call("switch", "turn_on", {self._warning})
  File "/usr/src/app/homeassistant/core.py", line 1070, in call
    self._hass.loop
  File "/usr/src/app/homeassistant/util/async_.py", line 138, in run_coroutine_threadsafe
    raise RuntimeError('Cannot be called from within the event loop')
RuntimeError: Cannot be called from within the event loop

The MQTT message is send from within a script:


alarm_arm_away:
  alias: Alarm Arm Away
  sequence:
    - service: mqtt.publish
      data:
        topic: 'home/alarm/set'
        payload: 'ARM_AWAY'

alarm_disarm:
  alias: Disarm Alarm
  sequence:
    - service: mqtt.publish
      data:
        topic: 'home/alarm/set'
        payload: 'DISARM'

My configuration is based on the default:


##[MQTT RELATED]
#[OPTIONAL] - False by default. Settings this to True will enable MQTT Mode. Uncomment options below to use See the README for guidance.
mqtt: True 
#[OPTIONAL] False by default. if true allows MQTT commands to disarm the alarm without a valid code.
override_code: True 
#[OPTIONAL] The MQTT topic HA will publish state updates to.
#state_topic: 'home/alarm' 
#[OPTIONAL] The MQTT topic HA will subscribe to, to receive commands from a remote device to change the alarm state.
command_topic: 'home/alarm/set' 
#[OPTIONAL] The maximum QoS level for subscribing and publishing to MQTT messages. Default is 0.
#qos: 0 
#[OPTIONAL] The payload to disarm this Alarm Panel. Default is “DISARM”.
payload_disarm: "DISARM" 
#[OPTIONAL] The payload to set armed-home mode on this Alarm Panel. Default is “ARM_HOME”.
payload_arm_home: "ARM_HOME" 
#[OPTIONAL] The payload to set armed-away mode on this Alarm Panel. Default is “ARM_AWAY”.
payload_arm_away: "ARM_AWAY" 
#[OPTIONAL] The payload to set armed-night mode on this Alarm Panel. Default is “ARM_NIGHT”.
payload_arm_night: "ARM_NIGHT" 

Can confirm the alarm_disarm script works as expected. Calling the alarm_arm_away script causes this error. Tried isolating the problem as well by calling the MQTT publish service directly using these parameters:

{
"topic":"home/alarm/set",
"payload":"ARM_AWAY"
}

Same error:

2018-10-29T11:04:11.236237936Z 2018-10-29 11:04:11 ERROR (MainThread) [homeassistant.core] Error doing job: Exception in callback <bound method MQTT._mqtt_handle_message of <homeassistant.components.mqtt.MQTT object at 0x7faf183d4f28>>
2018-10-29T11:04:11.236292353Z Traceback (most recent call last):
2018-10-29T11:04:11.236304191Z   File "uvloop/cbhandles.pyx", line 66, in uvloop.loop.Handle._run
2018-10-29T11:04:11.236312654Z   File "/usr/src/app/homeassistant/components/mqtt/__init__.py", line 775, in _mqtt_handle_message
2018-10-29T11:04:11.236320738Z     subscription.callback, msg.topic, payload, msg.qos)
2018-10-29T11:04:11.236328408Z   File "/usr/src/app/homeassistant/core.py", line 327, in async_run_job
2018-10-29T11:04:11.236336480Z     target(*args)
2018-10-29T11:04:11.236343735Z   File "/config/custom_components/alarm_control_panel/bwalarm.py", line 668, in message_received
2018-10-29T11:04:11.236351601Z     self.alarm_arm_away('')
2018-10-29T11:04:11.236359243Z   File "/config/custom_components/alarm_control_panel/bwalarm.py", line 485, in alarm_arm_away
2018-10-29T11:04:11.236368628Z     self.process_event(Events.ArmAway)
2018-10-29T11:04:11.236376610Z   File "/config/custom_components/alarm_control_panel/bwalarm.py", line 577, in process_event
2018-10-29T11:04:11.236384942Z     self._hass.services.call("switch", "turn_on", {self._warning})
2018-10-29T11:04:11.236391272Z   File "/usr/src/app/homeassistant/core.py", line 1070, in call
2018-10-29T11:04:11.236395969Z     self._hass.loop
2018-10-29T11:04:11.236400297Z   File "/usr/src/app/homeassistant/util/async_.py", line 138, in run_coroutine_threadsafe
2018-10-29T11:04:11.236404850Z     raise RuntimeError('Cannot be called from within the event loop')
2018-10-29T11:04:11.236409428Z RuntimeError: Cannot be called from within the event loop
2018-10-29T11:04:11.237437077Z /usr/src/app/homeassistant/util/async_.py:29: RuntimeWarning: coroutine 'ServiceRegistry.async_call' was never awaited
2018-10-29T11:04:11.237453721Z   return loop.run_until_complete(main)

This is a critical error because HA is unable to recognise the alarm panel afterwards. (the following log is generated when clicking on the ARM Away button in the alarm panel frontend.

2018-10-29T11:05:00.034213092Z 2018-10-29 11:05:00 WARNING (MainThread) [homeassistant.core] Unable to find service alarm_control_panel/
TheCellMC commented 6 years ago

Same issue here

adipose commented 6 years ago

The issue would seem to be the syntax changes for async functions in .82. I was able to avoid the bug by updating as follows:

--- tmp\bwalarm.py  2018-11-12 21:47:39.000000000 -0800
+++ bwalarm.py  2018-11-13 00:12:27.000000000 -0800
@@ -214,14 +214,13 @@
     vol.Optional(CONF_OVERRIDE_CODE, default=False):            cv.boolean,
     #-----------------------------END------------------------------------
 }, _state_validator))

 _LOGGER = logging.getLogger(__name__)

-@asyncio.coroutine
-def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
+async def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
     #Setup MQTT if enabled
     mqtt = None
     if (config[CONF_MQTT]):
         import homeassistant.components.mqtt as mqtt
     alarm = BWAlarm(hass, config, mqtt)
     hass.bus.async_listen(EVENT_STATE_CHANGED, alarm.state_change_listener)
@@ -638,14 +637,13 @@
             if now() > self._passcode_timeoutat:
                 self._panel_locked = False
                 self._passcode_timeoutat = None
                 self._passcodeAttemptNo = 0
                 self.schedule_update_ha_state()

-    @asyncio.coroutine
-    def async_added_to_hass(self):
+    async def async_added_to_hass(self):
         """Subscribe mqtt events.
         This method must be run in the event loop and returns a coroutine.
         """
         if (self._mqtt):
             async_track_state_change(
                 self.hass, self.entity_id, self._async_state_changed_listener
@@ -672,13 +670,12 @@
                 _LOGGER.warning("[ALARM/MQTT] Received unexpected payload: %s", payload)
                 return
         if (self._mqtt):
             return self.mqtt.async_subscribe(
                 self.hass, self._command_topic, message_received, self._qos)

-    @asyncio.coroutine
-    def _async_state_changed_listener(self, entity_id, old_state, new_state):
+    async def _async_state_changed_listener(self, entity_id, old_state, new_state):
         """Publish state change to MQTT."""
         if (self._mqtt):
             self.mqtt.async_publish(self.hass, self._state_topic, new_state.state,
                            self._qos, True)
             _LOGGER.debug("[ALARM/MQTT] State changed")
danobot commented 6 years ago

@adipose Are you able to PR this fix? Happy to test on my system as well

adipose commented 6 years ago

@danobot I could do that, but I have to be honest: my alarm is not updating when the mqtt messages arrive. I believe my update is correct, insofar as the new syntax for async has changed. If this change is not made, HA will not even boot because it gets stuck in the event loop.

What's very strange, though, is the manual_mqtt alarm does not have the async_setup_platform set up as an async method. Everywhere else in the code base async_setup_platform is type async, except for manual_mqtt. Thus I speculated that bwalarm would also need to be non-async, but doing that results in the hang of HA.

I will PR my fix, if I get mqtt working. For now, if you want to use my patch, you simply need to edit your bwalarm.py and remove all the lines that say:

@asyncio.coroutine

Then the "def" that immediately follows should be prefixed with "async."

adipose commented 6 years ago

It's working now.

https://github.com/gazoscalvertos/Hass-Custom-Alarm/pull/52

I had to turn all the internal calls to async_ but leave the outer async_setup_platform without the async prefix.

Tyre88 commented 5 years ago

It's working now with override_code aswell.

65

I needed that since my mqtt alarm panel doesn't have code for arming, only for disarming.