
Sem dúvida, o Apple iOS continua sendo um dos sistemas operacionais móveis mais populares, o que significa que os sistemas de automação modernos devem poder se integrar nesse ecossistema e fornecer a capacidade de interagir. É exatamente para isso que a estrutura Homekit foi projetada, que permite trabalhar com dispositivos inteligentes na tela do iPhone / iPad / iWatch e, mais recentemente, no Mac (macOS Mojave).
A maioria dos sistemas de automação (não gosto do nome de marketing "casa inteligente") há muito tempo inclui módulos para integração com o Homekit, mas mesmo um usuário treinado nem sempre consegue descobrir como disponibilizar seu dispositivo no aplicativo Casa (ou Eve).
Hoje eu vou lhe dizer como fazer essas manipulações no sistema ioBroker (este é um sistema de automação aberto e gratuito). Mas, para não dar estupidamente todos os muitos exemplos de dispositivos, quero explicar alguns princípios e mostrar abordagens, sabendo quais você pode implementar facilmente outros exemplos.
"Conhecer alguns princípios compensa facilmente a ignorância de alguns fatos."
Claude Adrian Helvetius
ioBroker. Drivers, dispositivos e status
Antes de tudo, quero explicar o que é um dispositivo no sistema ioBroker e como ele é apresentado.
Deixe-me lembrá-lo de que o sistema ioBroker é modular e que os módulos de extensão são chamados de drivers (ou adaptadores). Um driver é um módulo de integração com algum dispositivo ou grupo de dispositivos, unido por uma funcionalidade, protocolo ou fabricante comum e, portanto, pode "arrastar" de um a vários dispositivos para o sistema ioBroker. Outro recurso é a capacidade de criar várias instâncias do mesmo driver, diferindo em qualquer configuração.
Mas cada dispositivo é único e inimitável, possui características e capacidades diferentes. Com base nisso, o ioBroker se concentra principalmente não no próprio dispositivo, mas em suas características, representadas por estados. Um estado é um objeto ioBroker interno que aceita e armazena um valor. Os sinônimos do estado podem ser considerados: sinais, atributos, características, propriedades, eventos. Exemplos de condições: “temperatura”, “nível de brilho”, “nível de bateria”, “sinalizador de inicialização”, “sinalizador de erro”, “sinalizador de pressão”, “sinalizador de pressão dupla”, etc. Assim, cada dispositivo é representado por muitos estados diferentes.

Os estados podem ser divididos em informativos - exibem informações do dispositivo e mutáveis - podem ser alterados pelo usuário ou script e enviam essas alterações ao dispositivo. Assim, quando algo muda no dispositivo - esses dados são exibidos nos estados e quando o estado muda do ioBroker (pelo usuário ou pelo script) - o dispositivo recebe um sinal sobre a alteração e deve responder de acordo (depende do próprio dispositivo e do driver com ele) obras).
Todos os estados do dispositivo são combinados em uma única árvore (registro) de estados. Eles são agrupados primeiro por dispositivo (em alguns casos, a canalização ainda é usada) e depois por instâncias de driver.
O conceito de tópicos do protocolo MQTT se encaixa facilmente em uma árvore de estados. Dessa forma, você pode conectar equipamentos adicionais ou sistemas de terceiros que suportam o protocolo MQTT. É suficiente instalar o driver MQTT - a ramificação correspondente aparecerá na árvore de estados.
E existem todos os tipos de serviços on-line que podem fornecer informações úteis e / ou possibilitar o controle de outros equipamentos (alarmes de carros, por exemplo). O resultado da interação com esses serviços também é representado como um conjunto de estados.

No total, um dispositivo no ioBroker é representado por um conjunto de estados que caracterizam o dispositivo e permitem interagir com ele.
Homekit Acessórios, serviços e especificações
Agora vá para o Homekit. Aqui é aplicada a classificação dos dispositivos, sua funcionalidade e características.

Acessórios é o equivalente a um dispositivo físico. O acessório possui uma categoria para atribuí-lo a um grupo específico.
Serviços é o equivalente à funcionalidade de um acessório. Um acessório pode ter vários serviços.
Os serviços indicam os recursos do dispositivo: lâmpada, bateria, botão, sensor de qualidade do ar, porta, filtro de ar, câmera ..
É o serviço que determina a exibição, o comportamento do dispositivo e o conjunto de características.
Característica é o equivalente dos atributos / propriedades que caracterizam um serviço. São as características que determinam se o dispositivo está ligado, o nível de brilho da lâmpada ou quantas vezes o botão é pressionado. Um único serviço pode ter muitas características.

Os aplicativos que funcionam com o Homekit leem os serviços e as características dos acessórios e, em seguida, exibem e permitem alterar os valores nas características por meio da interface do usuário. Os valores alterados são enviados aos dispositivos Homekit para aplicá-los e, a partir dos dispositivos Homekit, respectivamente, também os valores das características são enviados com algumas alterações do lado do dispositivo.
No total, o dispositivo no HomeKit parece ser um acessório com um conjunto de serviços e recursos.
Yahka. Juntamos o conceito
Para trabalhar com o Homekit, o ioBroker usa o driver Yahka ( módulos adicionais devem ser instalados antes da instalação) - um complemento para uma biblioteca conhecida https://github.com/KhaosT/HAP-NodeJS , que também cria o popular projeto HomeBridge. Esta biblioteca foi projetada para criar um gateway / ponte virtual que fornece um conjunto de dispositivos virtuais no HomeKit. Configurando os dispositivos e serviços virtuais de acordo, definindo os valores das características, obtemos o dispositivo finalizado no Homekit e no aplicativo Home e também podemos pedir à Siri para gerenciá-lo.
O driver Yahka foi desenvolvido apenas para configurar acessórios, adicionar serviços a eles e indicar a correspondência de características (HomeKit) e estados (ioBroker).
Mas primeiro, após a instalação, você precisa configurar o gateway e inseri-lo no aplicativo Home. Após a configuração, todos os dispositivos adicionados ao gateway serão automaticamente adicionados à Casa. Para fazer isso, especifique "Nome do dispositivo" (é desejável especificar apenas letras latinas) e lembre-se do código PIN (ou defina seu próprio).

Vamos ao aplicativo inicial e adicionamos um novo acessório. Agora vamos aos dispositivos. Tudo ficaria bem se o conjunto de estados do dispositivo no ioBroker correspondesse claramente ao conjunto de serviços e recursos do HomeKit. E seria ainda melhor se os valores nos estados fossem adequados para os valores das características. Mas, muitas vezes, não é assim, e você precisa criar maneiras incomuns de atracar. Falarei sobre alguns deles abaixo, e você terá que implementar todas as outras opções "à imagem e semelhança".
Por conveniência, criei um documento com a tradução de serviços e tipos, bem como os possíveis valores das características. Todos os tipos e serviços utilizados correspondem à biblioteca HAP-NodeJS .
Sensor de temperatura
Este é o exemplo mais simples - você só precisa ter um estado contendo o valor numérico da temperatura. Pode ser obtido de qualquer lugar: a partir de sensores ou de serviços de Internet (clima).
Você precisa adicionar um dispositivo da categoria Sensor, adicionar o serviço TemperatureSensor ao dispositivo e dar um nome a esse serviço. Existem 5 características neste serviço, das quais a mais importante para nós é CurrentTemperature.


Basta indicar o nome do estado correspondente à temperatura na característica CurrentTemperature.
Adicione o serviço de umidade HumiditySensor aqui também e um ícone de acessório separado será criado no Homekit.

Salve e pronto. Agora você pode ligar para a Siri e perguntar sobre temperatura e umidade.

Bateria
Outro serviço simples. Seu truque é que ele pode ser adicionado a praticamente qualquer acessório. Adicione o serviço BatteryService e indique na característica BatteryLevel um estado contendo a porcentagem de carga da bateria. Depois disso, os dados de cobrança aparecerão nos dados adicionais sobre o dispositivo.

Você pode definir imediatamente o sinal de "carga baixa" (característica StatusLowBattery), se o valor do estado especificado for igual a 1, o ícone correspondente será exibido na imagem do dispositivo.
Mas e se você não tiver esse estado, mas quiser ver o ícone de bateria fraca? É necessário criar esse estado manualmente ou por um script e indicar o estado criado nas características.
Agora resta apenas definir corretamente o valor verdadeiro neste estado. Para fazer isso, usaremos o script - ele será verdadeiro quando a bateria atingir 30%.
createState(""); on({id: "zigbee.0.00158d0001f41725.battery", change: "ne"}, function (obj) { var value = obj.state.val; setState("javascript.0.", (value <= 30)); });
Após a primeira execução, o script criará um estado e poderá ser selecionado nas características.

Este sinal será exibido nas imagens de acessórios

e detalhes do dispositivo Lâmpadas
As lâmpadas são diferentes - brilhantes, quentes e vermelhas. Existem 4 casos:
- Simples - controlado por ligar e desligar
- Regulável - também controlado pelo nível de brilho
- Com a temperatura - é possível controlar a temperatura do brilho
- Cor - você pode controlar a cor do brilho
Para cada um desses casos, há uma característica correspondente no serviço Lightbulb:
- On - on / off
- Brilho - nível de brilho
- Matiz - sombra
- Saturação - Saturação
- ColorTemperature - temperatura da cor
No caso simples, na característica "On", indicamos o estado responsável por ligar e desligar.

Se a lâmpada estiver regulável, indicamos adicionalmente o status com o nível de brilho.

Além de atribuir estados corretos, é importante observar o intervalo de valores aceitáveis!
Exemplo: em alguns casos, o estado responsável pelo brilho da lâmpada pode assumir valores de 0 a 255, mas no Homekit esses valores são limitados a um intervalo de 0 a 100. Nesse caso, você pode usar as funções de conversão do driver Yahka. A função "level255" apenas converte o intervalo dos valores 0..255 para o intervalo 0..100 (e vice-versa).
As seguintes dificuldades podem surgir se a lâmpada for colorida, mas a cor usada for RGB. Pode ser três estados diferentes ou um número (ou sequência). Nesse caso, você precisará converter de um espaço de cores RGB em outro espaço XYB (esse espaço é usado pelo HomeKit) ou no plano XY.
Para fazer isso, você precisa criar 2 novos estados (Matiz e Saturação), nos quais converteremos os valores do estado RGB e vice-versa.
O script resultante para a cor é A temperatura da cor pode ser mais fácil - se o intervalo de valores disponíveis para a sua lâmpada for conhecido, ele poderá ser convertido no intervalo disponível para o HomeKit (através da função scaleInt ).


Termostato
Termostato - um dispositivo para manter a temperatura definida (serviço Termostato). Por conseguinte, a principal característica do termostato é a temperatura desejada (TargetTemperature). Além da temperatura definida, pode ser indicada a temperatura atual (CurrentTemperature), que é de natureza informativa (já que o dispositivo apenas lê a partir dos sensores).
No aplicativo inicial, a temperatura alvo é definida no termostato e a temperatura atual é monitorada. No meu termostato (Zont), havia apenas esses dois estados - eles estavam disponíveis na API da nuvem de serviço.
Para a beleza de exibir o dispositivo no HomeKit, tive que adicionar algumas constantes: o estado atual do aquecimento está ativo (1), o estado-alvo do aquecimento é automático (3).


Portões
Com uma porta de garagem (serviço GarageDoorOpener), tudo é mais complicado do que com um termostato.
Das características disponíveis, o portão possui um estado de destino (TargetDoorState), que indica nosso desejo de que o portão seja "aberto" ou "fechado". Mas você também precisa exibir corretamente o estado atual do portão (CurrentDoorState): eles estão abertos ou fechados, ou talvez eles sejam abertos ou fechados?
No meu caso, os portões foram abertos através do mqtt no ioBroker com vários estados de informação:
- sinal de abertura do portão (OB)
- sinal de movimento do portão (LW)

Graças a esses estados, você pode calcular o status atual do gate:
- se não houver OB nem DV, então os portões estão fechados
- se não houver OB e houver um DV, os portões se abrirão
- se houver um OB e nenhum DV, os portões estão abertos
- se houver um OB e um DV, o portão será fechado
Para enviar um sinal para abrir e fechar o portão, tenho dois estados separados (seria possível gerenciar com um estado, mas tenho dois), que enviam uma mensagem via mqtt para o controlador de controle do portão:
- sinal de abertura
- sinal de fechamento
Para enviar um sinal, você precisa simular um botão "clique": defina o valor como true e, após algum tempo, redefina-o como false. Nesse sentido, para integrar com o HomeKit, foi necessário criar outro estado - o "estado alvo do portão", quando alterado, o sinal correspondente será enviado.
O sinal de abertura do portão pode ser substituído pelo estado de destino (ou seja, qual é o objetivo da meta):
- se a CA estiver “fechada” e não houver DV, o portão estará fechado
- se a CA estiver "fechada" e houver um DV, os portões se abrirão
- se a autoridade de certificação estiver "aberta" e não houver DV, o portão estará aberto
- se a autoridade de certificação estiver "aberta" e houver um DV, o portão será fechado
Também criaremos um estado separado "estado atual do portão" e o preencheremos no script, dependendo do valor dos sinais e do estado de destino.
Script de mudança de estado para portas de garagem createState("gate_0.current");
Depois de executar o script, você pode configurar as características do serviço da porta da garagem:


Camera
Para adicionar uma câmera ao HomeKit, será usado o método "clássico". A transmissão da imagem da câmera através do módulo ffmpeg é organizada. Por meio dele, o fluxo de entrada será codificado, criptografado e entregue ao Homekit.
Primeiro de tudo, você precisa instalar o ffmpeg no servidor em que o ioBroker está localizado.
Para cada plataforma, ela é instalada de maneiras diferentes, você pode montá-la a partir da fonte ou procurar uma montagem pronta, por exemplo, aqui: https://www.johnvansickle.com/ffmpeg/ Deve ter um codificador libx264. Você pode verificar o codificador após instalar o ffmpeg com o comando:
ffmpeg -codecs | grep 264
Os resultados devem conter uma linha do formulário:
DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 h264_v4l2m2m h264_vdpau ) (encoders: libx264 libx264rgb h264_v4l2m2m )
Para o Raspberry Pi 3, você pode usar o conjunto pronto , que possui um codec com suporte para codificação de hardware da GPU (h264_omx, consome menos recursos). Coloque assim:
wget https://github.com/legotheboss/YouTube-files/raw/master/ffmpeg_3.1.4-1_armhf.deb sudo dpkg -i ffmpeg_3.1.4-1_armhf.deb
Os dois codecs estão presentes neste assembly: libx264 e h264_omx
Em seguida, você precisa obter o endereço do fluxo da câmera que precisa ser transmitido (esta etapa está além do escopo deste artigo). Por exemplo, você pode usar um fluxo público pronto .
Agora adicione a câmera a Yahka, indique o endereço do fluxo e, se necessário, altere os parâmetros do codec, tamanho da imagem e taxa de quadros.
Importante: combinações de parâmetros são muito importantes para a exibição correta da câmera no Homekit e dependem da câmera e do fluxo. Também afeta o desempenho do sistema, pois O processo de execução do ffmpeg consome muitos recursos.


As câmeras são adicionadas como dispositivos separados fora do gateway e devem ser adicionadas da mesma maneira que o gateway 

Bônus
Como bônus, falarei sobre o uso incomum da transmissão de câmeras.
Usando o mesmo ffmpeg, em vez da câmera, você pode tentar transmitir a imagem, qualquer imagem. Essas imagens também podem ser combinadas com o fluxo de vídeo. Você pode exibir texto, gráficos e outras informações na imagem.

Como resultado, você pode obter um painel interessante. E se você atualizar a imagem periodicamente, obterá dados dinâmicos.
Como exemplo, eu trouxe um gráfico de alterações em alguns indicadores na forma de uma imagem (arquivo em disco). Este gráfico é atualizado uma vez por minuto e substitui a imagem no arquivo.
(as funções createImage1, createImage2, a formação de um gráfico e a imposição de texto em uma imagem estão além do escopo deste artigo, mas darei uma dica).Eu vou te dizer como você pode obter um gráfico na forma de uma imagem.
O IoBroker possui uma maneira padrão de criar gráficos - o driver Flot. Este driver é emparelhado com um driver da web e exibe o resultado em um navegador. Mas, para obter o gráfico criado no servidor (no script) como uma imagem, é necessário um driver PhantomJS adicional, que captura uma "captura de tela" da página (na qual desenharemos um gráfico de Flot).
Mas vou falar sobre uma maneira alternativa de criar gráficos no servidor em um script.
Existe uma biblioteca Chart.js http://www.chartjs.org/ que permite desenhar gráficos bonitos no navegador (exemplos http://www.chartjs.org/samples/latest/ ).
Para desenhar, ele usa a “tela” (tela, tela) do navegador. Portanto, para desenhar usando essa biblioteca no servidor, você precisa usar a versão “server” dos objetos “canvas” e DOM. É isso que o pacote chartjs-node faz ( https://github.com/vmpowerio/chartjs-node ).
A principal dependência desse pacote é o pacote canvas ( https://github.com/Automattic/node-canvas ), que deve ser instalado globalmente (ou na pasta iobroker). É importante instalar todas as dependências da plataforma em que você coloca https://github.com/Automattic/node-canvas#compiling .
Depois disso, você pode adicionar os módulos chart.js, chartjs-node nas configurações do driver javascript. Eles devem instalar corretamente, sem erros. Caso contrário, lide com os erros e resolva-os.
E então, você pode escrever um script.
Abaixo está um script para um exemplo, como inclui o uso do driver Histórico e usa nomes de estado específicos.
Atenção! O script tem construções complicadas para iniciantes - Promessa. Essa é uma maneira conveniente de não escrever funções com retorno de chamada, mas criar cadeias de etapas. Portanto, por exemplo, é conveniente fazer isso para obter dados do histórico do estado.
'use strict'; const ChartjsNode = require('chartjs-node'); function sendToPromise(adapter, cmd, params) { return new Promise((resolve, reject) => { sendTo(adapter, cmd, params, (result) => { resolve(result); }); }); }

A imagem em miniatura é atualizada aproximadamente uma vez por minuto, portanto, definiremos a imagem para ser atualizada a cada 10 segundos:
var fs = require('fs'); // 10 schedule("*/10 * * * * *", () => { createImage1('/tmp/1_new.jpg', ()=> { fs.renameSync('/tmp/1_new.jpg', '/tmp/1.jpg'); }); createImage2('/tmp/2_new.jpg', ()=> { fs.renameSync('/tmp/2_new.jpg', '/tmp/2.jpg'); }); });
A peculiaridade é que, no processo de transmissão da imagem, é necessário substituir a imagem com rapidez suficiente para que o ffmpeg não trate :) Portanto, a imagem é formada primeiro em um arquivo e, em seguida, renomeada para a usada para tradução.
Agora, nas configurações da câmera, especifique o nome do arquivo gerado em vez do endereço do fluxo e adicione as configurações para que a imagem seja “atualizada” (parâmetro “-loop 1”). Isso é configurado nas propriedades avançadas da câmera. Essas propriedades nada mais são do que opções de linha de comando para executar o ffmpeg. Portanto, combinações de parâmetros devem ser encontradas na documentação e nos exemplos do ffmpeg.
As propriedades são divididas em 2 tipos: para receber uma "visualização" (uma pequena imagem da câmera) e para transmitir. Portanto, você pode especificar arquivos de origem de imagem diferentes, por exemplo, com detalhes diferentes.


Conclusão
ioBroker . , . , , .
, Yahka , Material. , HomeKit.
Yahka, HomeKit — Ham, HomeBridge . .