Sensor Bayesian. Estadística para tu sistema domótico Home Assistant. Veremos cómo usamos nuestros propios datos para crear un sensor basado en el Teorema de Bayes y calcular probabilidades.
En nuestra anterior entrada vimos cómo optimizar la cantidad de registros que almacenamos en nuestra base de datos de Home Assistant.
Hoy veremos precisamente cómo podemos usar esos mismos datos para crear algo nuevo en nuestro sistema, particularizado con patrones de uso de nuestro hogar. Conoceremos el sensor Bayesian. Estadística para para tu sistema domótico.
No se trata esta vez de copiar y pegar. Uso datos reales y con un fin muy concreto, pero sí que os va a servir de inspiración para realizar vuestros propios cálculos y por favor, ponedlos en los comentarios para que también me den ideas.
Como de costumbre, os adelanto lo que queremos conseguir para que tengamos una visión de conjunto: Queremos configurar un sensor «inteligente» y estimar la probabilidad de que algo suceda cuando no tenemos forma de medirlo de forma exacta.
Me explico con un ejemplo sencillo:
No tiene sentido que estimemos la probabilidad de que la TV del salón esté encendida si ya podemos ver el estado de dicho dispositivo en el sistema (ver un post anterior). Ya sabremos con un 100% de certeza si ocurre o no el evento.
Pero, ¿qué pasa si queremos ver la probabilidad de que en una zona de la casa se detecte movimiento de intrusión? No sabemos si el movimiento detectado es de alguien de la familia o de un caco… en otras palabras, no podemos tener la certeza y por tanto es caldo de cultivo para trabajar con probabilides. Es lo que vamos a hacer.
El enfoque tradicional sería configurar un modo alerta, en una determinada franja horaria por la noche, o combinado con los fines de semana, en la que pensemos que no es normal que alguien esté presente y activar a continuación una sirena o una notificación.
Nosotros vamos a subir un nivel la complejidad, dejando que el sistema decida cuándo debe dejar activado el modo de alerta y nos preavise con un mensaje de Telegram a nuestro teléfono usando el método bayesiano.
Dotaremos al sistema Home Assistant con algo de inteligencia usando la probabilidad condicional y nuestros propios datos.
Usaremos para ello el sensor tipo Bayes ya integrado en Home Assistant. Sigue leyendo, pues mezclaremos conceptos de estadística con la domótica.
Por cierto, la idea de seguridad por capas aquí también aplica, y si quisiéramos en serio evaluar y aumentar la seguridad (o minimizar el nivel de riesgo) habría que usar principios de seguridad funcional (en otro post).
Tabla de contenidos
- 1. Cálculo en Home Assistant. Entendiendo el teorema de Bayes
- 2. Análisis de datos. Probabilidad inicial en el teorema de Bayes.
- 3. Observación 1. Tabla de probabilidades y template en Home Assistant
- 4. Observación 2. TV funcionando
- 5. Observación 3. Sin detección de movimiento durante 30 minutos
- 6. Binary sensor Bayesian. Juntando todo
1. Cálculo en Home Assistant. Entendiendo el teorema de Bayes
La implementación del teorema de Bayes es sencilla en lo que se refiere al cálculo, pero algunas veces es complicada de entender.
De ahora en adelante, cuando hablemos de probabilidad usaremos medidas en tanto por uno (0.02 por ejemplo, sobre todo en los cálculos) o su equivalente en porcentaje (2% por ejemplo, sobre todo para presentar resultados). Nunca con unidades.
Básicamente lo que nos dice el teorema de Bayes es algo de sentido común: Si existe una probabilidad X de que algo suceda, y no conocemos nada más, pues la probabilidad es X (obvio). Pero si conocemos algún dato relacionado (una observación , algo que podamos traducir en verdadero o falso), alteramos nuestro conocimiento inicial y ajustamos al alza o a la baja nuestra previsión inicial X.
Si la probabilidad de que un día llueva es digamos un 10%, pero además conocemos que ha llovido el día anterior, y que es invierno,…. pues eso, todo suma o baja.
Lo interesante del teorema es que nos dice exactamente en qué medida sube o baja nuestra probabilidad inicial simplemente con que le digamos 2 datos de cada observación:
- prob_given_true = Probabilidad de que la observación sea cierta, si damos por sentado que ese evento inicial que queremos medir es cierto.
- prob_given_false = Probabilidad de que la observación sea falsa, si damos por sentado que ese evento inicial que queremos medir es cierto.
- NO, repito NO tienen porqué sumar 1 ambas probabilidades.
En el caso de nuestra integración en Home Assistant, al ser un sensor binario, le tendremos que decir además a partir de qué probabilidad consideramos como verdadero el resultado (probability_threshold).
Vamos a particularizar en nuestro caso:
- Lo que queremos conocer, y que no podemos medir, es la probabilidad de que una zona de la casa esté en estado de alerta.
- La probabilidad inicial (prior). Luego veremos cómo estimamos esta importante probabilidad inicial en base a nuestros propios datos.
- Umbral de probabilidad (probability_threshold). Para estar seguros y no provocar muchos falsos positivos estableceremos el nivel por encima del 95% para activar nuestro estado de alerta.
- Las observaciones que usaremos serán:
- Observación 1: La probabilidad de que la presencia en la zona en una hora determinada sea menor del 5%. Es decir, ajustaremos la probabilidad inicial teniendo en cuenta los datos históricos de ocupación de esa zona.
- Observación 2: Estado ‘on’ de la TV principal. Es una observación muy indicada, pues si la TV está encendida es probable que no tengamos que establecer ninguna alerta.
- Observación 3: Sin movimiento en otra zona de la casa durante 30 minutos. Si hay alguien levantado es menos probable que entre un caco, y al contrario, si no hay nadie en casa pues es más probable que queramos esa alerta.
2. Análisis de datos. Probabilidad inicial en el teorema de Bayes.
Para no repetirnos, de nuevo os hago referencia al post sobre cómo optimizar la base de datos sqlite, donde explicábamos paso a paso las claves para extraer datos y cómo guardarlos en un fichero .csv que podremos tratar más fácilmente.
El hardware principal que usamos es este fiable y barato sensor de movimiento:
- Detecta el movimiento de personas y animales.
- Pequeño y discreto. Se puede colocar fácilmente.
- Suena la alarma al detectar el movimiento.
- Se puede activar y desactivar a tu dispositivo.
En nuestro caso concreto usaremos el sensor de detección de movimiento en la zona que queremos proteger, pero recordad que la idea es que os sirva de inspiración para otros usos:

Partiremos por tanto del fichero .csv exportado solo con los datos de activación de nuestro sensor (binary_sensor.sensormov_2_occupancy)
En concreto tenemos 465 detecciones de movimiento (filas en nuestro fichero .csv con estado=»on») en esa zona, obtenidos en un período de prueba de 10 días.
Al agrupar según horas y días de la semana vemos que hay 168 franjas disponibles (24h x 7 días = 168), de los cuales hemos detectado movimiento en 61 de las 168 horas posibles.
Por tanto, nuestra probabilidad inicial (prior) la establecemos en 0.36 (61/168) como punto de partida.
3. Observación 1. Tabla de probabilidades y template en Home Assistant
Esta será nuestra observación más elaborada, pues tendremos que crearnos un template específico.
Veremos primero cómo obtener nuestra tabla de probabilidad de ocupación, y depués nos metemos en los detalles de hacer un template para leerla en Home Assistant, para luego usar este dato en nuestro sensor basado en el teorema de Bayes.
De nuestro fichero csv de datos, hacemos una clasificación (el tratamiento de este fichero .csv en excel no entraña problema, pues podemos crear una pivot-table, aunque también se puede tratar en python si estáis más familiarizados).
Por cada hora en un día de la semana concreto, dividiremos la cantidad de detecciones en esa hora entre el total de detecciones en el día.
De esta manera, tendremos una aproximación muy buena a la probabilidad de que una persona «legítima» active nuestro sensor de movimiento en cada hora/día concreto. Además hemos puesto una probabilidad mínima de 0.01 en aquellas horas sin detección para ser más realistas:

Por ejemplo: La probabilidad de que se detecte movimiento de alguien de la familia un lunes a las 13:25 es del 8% (0.08)
En el fichero configuration.yaml en Home Assistant escribiremos lo siquiente para creal el sensor prob_det_mov_2:
- platform: template
sensors:
prob_det_mov_2:
value_template: "
{% set lun=[0.01,0.01,0.01,0.01,0.01,0.14,0.01,0.01,0.01,0.08,0.16,0.17,0.26,0.08,0.02,0.03,0.01,0.03,0.01,0.02,0.01,0.01,0.01,0.01] %}
{% set mar=[0.01,0.01,0.01,0.01,0.02,0.14,0.01,0.01,0.01,0.18,0.09,0.23,0.14,0.05,0.01,0.06,0.02,0.01,0.04,0.02,0.02,0.01,0.01,0.01] %}
{% set mie=[0.01,0.01,0.01,0.03,0.01,0.26,0.2,0.01,0.01,0.29,0.03,0.01,0.06,0.11,0.01,0.01,0.01,0.03,0.01,0.01,0.01,0.01,0.01,0.01] %}
{% set jue=[0.01,0.01,0.01,0.01,0.01,0.16,0.08,0.01,0.01,0.08,0.08,0.04,0.27,0.2,0.01,0.01,0.01,0.08,0.01,0.01,0.01,0.01,0.01,0.01] %}
{% set vie=[0.01,0.01,0.01,0.01,0.01,0.13,0.01,0.01,0.01,0.13,0.1,0.04,0.04,0.08,0.35,0.01,0.01,0.01,0.01,0.06,0.08,0.01,0.01,0.01] %}
{% set sab=[0.01,0.01,0.01,0.01,0.01,0.01,0.16,0.01,0.01,0.01,0.01,0.01,0.08,0.01,0.01,0.01,0.01,0.01,0.01,0.48,0.28,0.01,0.01,0.01] %}
{% set dom=[0.01,0.01,0.01,0.01,0.01,0.01,0.01,0.03,0.27,0.14,0.11,0.01,0.16,0.01,0.03,0.09,0.01,0.01,0.08,0.06,0.03,0.01,0.01,0.01] %}
{%set diasem=now().weekday()%}
{%if diasem==0 %}
{{lun[now().hour]}}
{%elif diasem==1 %}
{{mar[now().hour]}}
{%elif diasem==2 %}
{{mie[now().hour]}}
{%elif diasem==3 %}
{{jue[now().hour]}}
{%elif diasem==4 %}
{{vie[now().hour]}}
{%elif diasem==5 %}
{{sab[now().hour]}}
{%elif diasem==6 %}
{{dom[now().hour]}}
{%endif%} "
Básicamente hemos definido con el formato de jinja las 7 listas (una para cada día de la semana) con 24 valores cada una, correspondientes a las 24 horas del día.
Luego usamos la función weekday() para decidir en qué lista miramos con la propia hora como índice. Tened en cuenta que por defecto lunes=0 hasta domingo=6
La implementación de esta tabla en Home Assistant es un primer paso para facilitar la creación de la observación, que haremos al final usando el sensor recién creado (prob_det_mov_2). Podemos instalarlo en Lovelace para verificar que funciona y que los valores que va tomando cada hora son los de la tabla:

4. Observación 2. TV funcionando
La segunda observación que usamos para afinar la primera es el estado de la TV principal de casa.
El uso en Home Assistant es directo al usar el estado de ‘media_player.tv_salon’ y diciendo cual de los 2 estados es el que que nos interesa considerar como observación como veremos más adelante. Por tanto, esta observación será verdadera cuando esté en estado ‘on’ (to_state: ‘on’)
5. Observación 3. Sin detección de movimiento durante 30 minutos
Esta parte directamente la pondremos en el sensor final, pues es tan corta que no merece la pena crear template aparte, a menos que lo vayáis a usar en otros sitios:
{{ ( (as_timestamp(now())-as_timestamp(states.binary_sensor.sensormov_1_occupancy.last_changed)) /60 ) | round(0) > 30 }}
Se entiende: la diferencia entre el timestamp actual y el del último cambio del sensor, lo pasamos a minutos, redondeamos y hacemos la comparación (<30)
6. Binary sensor Bayesian. Juntando todo
Ahora vamos finalmente con el sensor binario basado en el teorema Bayes.
Lo configuramos con el siguiente código en el fichero configuration.yaml.
Recordad que ya no es necesario resetear todo, pues hay una opción específica para cargar este tipo de sensores:

Os pongo la configuración:
binary_sensor:
- platform: 'bayesian'
name: 'prob_cond_det_mov_2'
prior: 0.36 #Probabilidad inicial
probability_threshold: 0.95 # Probabilidad de estado de alerta > 95%
observations:
- entity_id: 'sensor.prob_det_mov_2'
platform: 'numeric_state'
prob_given_true: 0.9 # Prob. histórica de movimiento (< 5%), dando por cierto que hemos de estar en estado de alerta
prob_given_false: 0.2 # Prob. histórica de movimiento (< 5%), dando por cierto que NO hemos de estar en estado de alerta.
below: 0.05 #por debajo de 5%
- entity_id: 'media_player.tv_salon'
platform: 'state'
prob_given_true: 0.01 # Prob. TV funcionando, dando por cierto que hemos de estar en estado de alerta. Ejemplo: Alguien se ha quedado dormido viendo la TV.
prob_given_false: 0.95 # Prob. Es muy probable que TV esté funcionando, dando por cierto que NO estamos en estado de alerta.
to_state: 'on'
- platform: 'template'
value_template: '{{ ( (as_timestamp(now())-as_timestamp(states.binary_sensor.sensormov_1_occupancy.last_changed)) /60 ) | round(0) > 30 }}'
prob_given_true: 0.9 # Prob. alta de no detectar movimiento durante 30 minutos, dando por cierto que hemos de estar en estado de alerta
prob_given_false: 0.05 # Prob. baja de detectar movimiento hace menos de 30 minutos, dando por cierto que NO hemos de estar en estado de alerta
La probabilidad incial (prior) se va transformando con cada observación que sea verdadera siguiendo este esquema para hacer nuestro análisis bayesiano:

Vamos afinando los pesos prob_given_true y prob_given_false para ajustar. Lo ideal sería basar este ajuste en frecuencias observadas, pero también podemos ir probando hasta que el comportamiento final (cuando debemos estar en estado de alerta o no) sea el deseado.
Tened en cuenta que cuanta mayor diferencia exista entre esos valores (prob_given_true y prob_given_false), mayor será la influencia en el resultado final. Intuitivamente lo vemos en un caso extremo. Si prob_given_true = prob_given_false = 0.5, serán sucesos independientes y tendremos una información que nos aporta lo mismo tanto si es cierta como si es falsa, y por tanto no tendrá influencia en el resultado.
Cuando ya estemos contentos con la predicción, podemos pasar a integrarlo en una automatización que nos active/desactive ese estado de alerta, y nos preavise por ejemplo con un mensaje de Telegram antes de hacer nada más…. Aquí os paso el post donde se explica la notificación con Telegram
La unión de estadística básica (como el visto con la estadística bayesiana sobre probabilidad condicionada) con la domótica es un campo poco investigado y que nos puede aportar mucho. Os animo a que miréis esta otra entrada con un ejemplo muy completo sobre el sensor statistcs
En un mundo lleno de «machine learning» y «deep learning», debemos recordar que Thomas Bayes hace unos 300 años ya nos dió una herramienta para hacer más «smart» nuestro hogar.