diff --git a/homeassistant/components/binary_sensor/bayesian.py b/homeassistant/components/binary_sensor/bayesian.py index ac328fd1f41..13908fb5472 100644 --- a/homeassistant/components/binary_sensor/bayesian.py +++ b/homeassistant/components/binary_sensor/bayesian.py @@ -102,7 +102,13 @@ class BayesianBinarySensor(BinarySensorDevice): self.current_obs = OrderedDict({}) - self.entity_obs = {obs['entity_id']: obs for obs in self._observations} + to_observe = set(obs['entity_id'] for obs in self._observations) + + self.entity_obs = dict.fromkeys(to_observe, []) + + for ind, obs in enumerate(self._observations): + obs["id"] = ind + self.entity_obs[obs['entity_id']].append(obs) self.watchers = { 'numeric_state': self._process_numeric_state, @@ -120,16 +126,17 @@ class BayesianBinarySensor(BinarySensorDevice): if new_state.state == STATE_UNKNOWN: return - entity_obs = self.entity_obs[entity] - platform = entity_obs['platform'] + entity_obs_list = self.entity_obs[entity] - self.watchers[platform](entity_obs) + for entity_obs in entity_obs_list: + platform = entity_obs['platform'] + + self.watchers[platform](entity_obs) prior = self.prior for obs in self.current_obs.values(): prior = update_probability(prior, obs['prob_true'], obs['prob_false']) - self.probability = prior self.hass.async_add_job(self.async_update_ha_state, True) @@ -140,20 +147,20 @@ class BayesianBinarySensor(BinarySensorDevice): def _update_current_obs(self, entity_observation, should_trigger): """Update current observation.""" - entity = entity_observation['entity_id'] + obs_id = entity_observation['id'] if should_trigger: prob_true = entity_observation['prob_given_true'] prob_false = entity_observation.get( 'prob_given_false', 1 - prob_true) - self.current_obs[entity] = { + self.current_obs[obs_id] = { 'prob_true': prob_true, 'prob_false': prob_false } else: - self.current_obs.pop(entity, None) + self.current_obs.pop(obs_id, None) def _process_numeric_state(self, entity_observation): """Add entity to current_obs if numeric state conditions are met.""" diff --git a/tests/components/binary_sensor/test_bayesian.py b/tests/components/binary_sensor/test_bayesian.py index 61b110f247f..3b403c3702f 100644 --- a/tests/components/binary_sensor/test_bayesian.py +++ b/tests/components/binary_sensor/test_bayesian.py @@ -73,8 +73,7 @@ class TestBayesianBinarySensor(unittest.TestCase): 'prob_false': 0.1, 'prob_true': 0.9 }], state.attributes.get('observations')) - self.assertAlmostEqual(0.77, - state.attributes.get('probability')) + self.assertAlmostEqual(0.77, state.attributes.get('probability')) assert state.state == 'on' @@ -155,6 +154,71 @@ class TestBayesianBinarySensor(unittest.TestCase): assert state.state == 'off' + def test_multiple_observations(self): + """Test sensor with multiple observations of same entity.""" + config = { + 'binary_sensor': { + 'name': + 'Test_Binary', + 'platform': + 'bayesian', + 'observations': [{ + 'platform': 'state', + 'entity_id': 'sensor.test_monitored', + 'to_state': 'blue', + 'prob_given_true': 0.8, + 'prob_given_false': 0.4 + }, { + 'platform': 'state', + 'entity_id': 'sensor.test_monitored', + 'to_state': 'red', + 'prob_given_true': 0.2, + 'prob_given_false': 0.4 + }], + 'prior': + 0.2, + 'probability_threshold': + 0.32, + } + } + + assert setup_component(self.hass, 'binary_sensor', config) + + self.hass.states.set('sensor.test_monitored', 'off') + + state = self.hass.states.get('binary_sensor.test_binary') + + self.assertEqual([], state.attributes.get('observations')) + self.assertEqual(0.2, state.attributes.get('probability')) + + assert state.state == 'off' + + self.hass.states.set('sensor.test_monitored', 'blue') + self.hass.block_till_done() + self.hass.states.set('sensor.test_monitored', 'off') + self.hass.block_till_done() + self.hass.states.set('sensor.test_monitored', 'blue') + self.hass.block_till_done() + + state = self.hass.states.get('binary_sensor.test_binary') + self.assertEqual([{ + 'prob_true': 0.8, + 'prob_false': 0.4 + }], state.attributes.get('observations')) + self.assertAlmostEqual(0.33, state.attributes.get('probability')) + + assert state.state == 'on' + + self.hass.states.set('sensor.test_monitored', 'blue') + self.hass.block_till_done() + self.hass.states.set('sensor.test_monitored', 'red') + self.hass.block_till_done() + + state = self.hass.states.get('binary_sensor.test_binary') + self.assertAlmostEqual(0.11, state.attributes.get('probability')) + + assert state.state == 'off' + def test_probability_updates(self): """Test probability update function.""" prob_true = [0.3, 0.6, 0.8]