Skip to content

Commit

Permalink
✨ [feature] disable by default entities that do not update
Browse files Browse the repository at this point in the history
Entities such as 'bluetooth' devices are declared as sensors but do
not seem to receive updates from the panel after that. We can thus
simply disable those by default, allowing people that want to see
them to enable them on a sensor-by-sensor basis, or even enable
all of them thanks to a new configuration option
`enable_static_sensors_by_default` that can be set to `true`.
  • Loading branch information
xaf committed Jan 7, 2023
1 parent 5b0e6ca commit a67d450
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 2 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,23 @@ With:
```
</details>

- <details><summary><strong>enable_static_sensors_by_default:</strong>
whether or not sensors that will not be updated by the panel (e.g. Bluetooth)
should be enabled by default in Home Assistant. Even if setting this to
<code>false</code>, you will have the ability to enable them on a
sensor-by-sensor basis in Home Assistant. If setting it to <code>true</code>,
you will also be able to disable them on a sensor-by-sensor basis in
Home Assistant.
Defaults to <code>false</code>.</summary>

```yaml
qolsys_panel:
# ...
enable_static_sensors_by_default: true
# ...
```
</details>


#### Optional configuration related to MQTT & AppDaemon

Expand Down
5 changes: 5 additions & 0 deletions apps/qolsysgw/mqtt/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from qolsys.sensors import QolsysSensorMotion
from qolsys.sensors import QolsysSensorSmokeDetector
from qolsys.sensors import QolsysSensorWater
from qolsys.sensors import _QolsysSensorWithoutUpdates
from qolsys.state import QolsysState
from qolsys.utils import defaultLoggerCallback
from qolsys.utils import find_subclass
Expand Down Expand Up @@ -477,6 +478,10 @@ def configure_payload(self, partition: QolsysPartition, **kwargs):
'availability_mode': 'all',
'availability': self.configure_availability,
'json_attributes_topic': self.attributes_topic,
'enabled_by_default': (
self._cfg.enable_static_sensors_by_default or
not isinstance(self._sensor, _QolsysSensorWithoutUpdates)
),
}

# As we have a unique ID for the panel, we can setup a unique ID for
Expand Down
1 change: 1 addition & 0 deletions apps/qolsysgw/qolsys/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class QolsysGatewayConfig(object):
'code_trigger_required': False,
'default_trigger_command': None,
'default_sensor_device_class': 'safety',
'enable_static_sensors_by_default': False,
}

def __init__(self, args=None, check=True):
Expand Down
6 changes: 5 additions & 1 deletion apps/qolsysgw/qolsys/sensors.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ def from_json_subclass(cls, subtype, data, common=None):
return cls(**common)


class _QolsysSensorWithoutUpdates(QolsysSensor):
pass


class QolsysSensorDoorWindow(QolsysSensor):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
Expand Down Expand Up @@ -228,7 +232,7 @@ def from_json(cls, data, common=None):
return cls.from_json_subclass('Panel Glass Break', data, common)


class QolsysSensorBluetooth(QolsysSensor):
class QolsysSensorBluetooth(_QolsysSensorWithoutUpdates):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

Expand Down
1 change: 1 addition & 0 deletions tests/end-to-end/fixtures/appdaemon/apps/apps.yaml.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ qolsys_panel:
panel_host: {% if IN_WSL %}host.docker.internal{% else %}localhost{% endif %}
panel_port: {{ PANEL_PORT }}
panel_token: ThisIsMyToken
enable_static_sensors_by_default: true
18 changes: 17 additions & 1 deletion tests/integration/test_qolsys_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ async def _check_partition_mqtt_messages(self, gw, partition_flat_name,
)

async def _check_sensor_mqtt_messages(self, gw, sensor_flat_name,
sensor_state, expected_device_class):
sensor_state, expected_device_class,
expected_enabled_by_default=True):
state = sensor_state

mqtt_prefix = f'homeassistant/binary_sensor/{sensor_flat_name}'
Expand Down Expand Up @@ -158,6 +159,7 @@ async def _check_sensor_mqtt_messages(self, gw, sensor_flat_name,
'unique_id': (f'qolsys_panel_p{state.partition_id}'
f'z{state.zone_id}'),
'device': mock.ANY,
'enabled_by_default': expected_enabled_by_default,
},
json.loads(mqtt_config['payload']),
)
Expand Down Expand Up @@ -284,6 +286,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_door',
sensor_state=sensor100,
expected_device_class='door',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 101 is properly configured'):
Expand All @@ -305,6 +308,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_window',
sensor_state=sensor101,
expected_device_class='door',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 110 is properly configured'):
Expand All @@ -326,6 +330,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_motion',
sensor_state=sensor110,
expected_device_class='motion',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 111 is properly configured'):
Expand All @@ -347,6 +352,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='panel_motion',
sensor_state=sensor111,
expected_device_class='motion',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 120 is properly configured'):
Expand All @@ -368,6 +374,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_glass_break',
sensor_state=sensor120,
expected_device_class='vibration',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 121 is properly configured'):
Expand All @@ -389,6 +396,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='panel_glass_break',
sensor_state=sensor121,
expected_device_class='vibration',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 130 is properly configured'):
Expand All @@ -410,6 +418,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_phone',
sensor_state=sensor130,
expected_device_class='presence',
expected_enabled_by_default=False,
)

with self.subTest(msg='Sensor 140 is properly configured'):
Expand All @@ -431,6 +440,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_smoke_detector',
sensor_state=sensor140,
expected_device_class='smoke',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 141 is properly configured'):
Expand All @@ -452,6 +462,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_co_detector',
sensor_state=sensor141,
expected_device_class='gas',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 150 is properly configured'):
Expand All @@ -473,6 +484,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_water_detector',
sensor_state=sensor150,
expected_device_class='moisture',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 200 is properly configured'):
Expand All @@ -494,6 +506,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_2nd_door',
sensor_state=sensor200,
expected_device_class='door',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 210 is properly configured'):
Expand All @@ -515,6 +528,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_freeze_sensor',
sensor_state=sensor210,
expected_device_class='cold',
expected_enabled_by_default=True,
)

with self.subTest(msg='Sensor 220 is properly configured'):
Expand All @@ -536,6 +550,7 @@ async def test_integration_event_info_summary_initializes_all_entities(self):
sensor_flat_name='my_heat_sensor',
sensor_state=sensor220,
expected_device_class='heat',
expected_enabled_by_default=True,
)

async def _test_integration_event_info_secure_arm(self, from_secure_arm,
Expand Down Expand Up @@ -867,6 +882,7 @@ async def test_integration_event_zone_event_zone_add(self):
{
'name': 'My Motion',
'device_class': 'motion',
'enabled_by_default': True,
'state_topic': 'homeassistant/binary_sensor/'
'my_motion/state',
'payload_on': 'Open',
Expand Down
1 change: 1 addition & 0 deletions tests/unit/qolsysgw/mqtt/test_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ def test_unit_sensor_configure_payload(self):
'name': 'Qolsys Panel',
},
'device_class': 'safety',
'enabled_by_default': True,
'json_attributes_topic': ('homeassistant/binary_sensor/'
'testsensor/attributes'),
'name': 'TestSensor',
Expand Down

0 comments on commit a67d450

Please sign in to comment.