A sua bomba de calor numa linha própria: quanto custa e depois automatize-a no HA

  • Testado no firmware v1.1.4
  • Intermédio

Escrito para o firmware v1.1.4. A versão atual é a v1.2.1, por isso alguns detalhes podem ser diferentes.

Parte 3 de 3 · Receitas de Home Assistant

Uma bomba de calor é normalmente a maior carga individual de uma casa, e aquela cujo custo é mais difícil de adivinhar. Funciona quando o tempo o exige, e não quando você quer, e numa tarifa de dia e de noite isso significa que a fatura depende de horas que você nunca escolheu. Medi-la no seu próprio circuito responde à primeira pergunta — quanto custa, de facto — e, quando o Home Assistant souber em que zona tarifária está o hub, pode fazer algo quanto à segunda.

O que precisa:

  • um hub RBgrid com o circuito da bomba de calor medido como ponto próprio;
  • um plano tarifário introduzido no hub — se ainda não o fez, comece por a sua própria tarifa horária;
  • o hub configurado para o seu fuso horário, com o relógio sincronizado: cada limite de zona neste guia é resolvido pelo relógio do hub, e não pelo seu (que fuso horário deve usar o hub);
  • um broker MQTT, com o Home Assistant ligado ao hub. Este guia começa depois de isso estar a funcionar. Se ainda não estiver, Um medidor de energia para o Home Assistant configura-o passo a passo — o broker, o formulário Settings → Home Assistant do hub e as primeiras entidades — e depois volte aqui.

Para a ligação e o dimensionamento das pinças, a montagem trifásica em o que custam a bomba de calor e o veículo elétrico cobre uma bomba de calor de ponta a ponta.

Segurança. Para qualquer trabalho dentro de um quadro elétrico, chame um eletricista qualificado.

1. Dê à bomba de calor o seu próprio ponto

Em Management → Points, associe o canal da bomba de calor e defina o seu Role como Heating/cooling. O papel é o que diz à aplicação que se trata de uma carga com horário próprio: o cartão de carga em standby, por exemplo, retira as linhas de aquecimento e de carregamento do veículo elétrico da base da casa antes de estimar o que está sempre ligado, porque uma bomba que funciona às 03:00 não está em standby.

Dê nome ao ponto antes de ele chegar ao Home Assistant. Isto importa mais do que parece — veja a §3.

As bombas monofásicas são um só ponto. Uma bomba trifásica é uma pinça por condutor, cada uma no módulo Basic dessa fase, associada como três pontos e agrupada; o guia trifásico explica o procedimento.

2. O que a aplicação mostra

Em Monitoring → Economics, com a bomba de calor selecionada, aparecem a sua energia e o seu custo por hora, hoje, ontem, nos últimos 7 dias, neste mês, no mês passado ou neste ano. O custo é o que o hub calculou à medida que a energia era consumida: a cada 15 minutos, ao preço da zona em vigor nesse momento, guardado com o registo horário. Nada é recalculado depois, por isso, quando o seu fornecedor alterar uma tarifa, o que a bomba custou no inverno passado continua a ser o que custou.

History na métrica Money coloca-a ao lado dos seus outros circuitos no mesmo período, e Download CSV leva os números consigo.

Quanto ao custo por zona: o Economics tem essa divisão, mas leia-a pelo que é — um total acumulado desde o último reinício do hub, que não acompanha o seletor de período. Responde a «como está a divisão neste momento», não a «quanto custou a bomba na zona da noite em outubro». Não existe uma vista mensal do custo por zona; para um mês, use o seletor de período e tire o total.

E antes de recorrer ao CSV para fazer isso por si: os registos guardados contêm energia e dinheiro por período, mas nenhum campo de zona — a divisão existe apenas no total acumulado. Por isso, a comparação entre noite e dia de um mês não é uma vista que lhe falte; é um valor que o hub não guarda.

3. Envie-o para o Home Assistant

Com o MQTT ligado, cada ponto associado aparece como um dispositivo próprio com oito sensores: corrente, potência, potência reativa, fator de potência e energia de entrada e de saída, tanto em contador vitalício como em contador diário. A energia entra no painel de energia em Individual devices diretamente — sem utility_meter, sem sensor de modelo. Use o contador vitalício Energy In, e não o (Day): os contadores diários são repostos à meia-noite local do hub, enquanto os totais vitalícios nunca diminuem e sobrevivem a um reinício ou a uma atualização de firmware, na memória do próprio hub. Uma reposição de fábrica apaga-os, e o mesmo acontece ao eliminar o ponto.

Duas coisas que lhe poupam uma noite:

  • O id da entidade fica fixo na primeira descoberta. Se renomear o ponto na aplicação depois, só muda o nome apresentado: um ponto descoberto primeiro como «UI7 I2» mantém sensor.rbgrid_ui7_i2_power. Pode renomear as entidades no Home Assistant, por isso não é permanente — é apenas trabalho que pode evitar. Dê-lhe nome antes de ligar o broker, ou renomeie as entidades no HA uma vez.
  • O papel não se transfere. Heating/cooling é um conceito da aplicação; no Home Assistant, o dispositivo da bomba de calor é exatamente igual a qualquer outro ponto. O que quiser fazer com o papel, faça-o do lado do RBgrid.

4. Torne a zona tarifária visível para o HA

O hub publica a sua zona tarifária atual, mas não como entidade descoberta — a descoberta cobre as medições, não a tarifa. A zona vive na trama de telemetria do hub, que é publicada a cada três segundos e não fica retida. Um sensor MQTT vai buscá-la. <MAC> são os doze caracteres hexadecimais do hub em minúsculas — os tópicos são sensíveis a maiúsculas, e o prefixo rbgrid/ é fixo:

yaml
mqtt:
  sensor:
    - name: "Tariff Zone"
      unique_id: ha_rbgrid_<MAC>_tariff_zone
      default_entity_id: sensor.rbgrid_tariff_zone
      state_topic: "rbgrid/<MAC>/telemetry"
      value_template: >-
        {% set t = value_json.get('system', {}).get('tariff') or {} %}
        {{ t.zone if t.zone is defined else None }}
      expire_after: 30
      availability:
        - topic: "rbgrid/<MAC>/status"
          payload_available: "online"
          payload_not_available: "offline"
      json_attributes_topic: "rbgrid/<MAC>/telemetry"
      json_attributes_template: >-
        {% set t = value_json.get('system', {}).get('tariff') or {} %}
        {{ {'plan_active': t.zone is defined,
            'time_src': value_json.get('time_src'),
            'buy_rate': t.get('buy_rate'), 'sell_rate': t.get('sell_rate'),
            'currency': t.get('currency'),
            'placeholder': t.get('placeholder', false)} | tojson }}
      device:
        identifiers: ["<MAC>"]
    - name: "Tariff Buy Rate"
      unique_id: ha_rbgrid_<MAC>_tariff_buy_rate
      default_entity_id: sensor.rbgrid_tariff_buy_rate
      state_topic: "rbgrid/<MAC>/telemetry"
      value_template: >-
        {% set t = value_json.get('system', {}).get('tariff') or {} %}
        {{ t.buy_rate if t.buy_rate is defined else None }}
      unit_of_measurement: "EUR/kWh"
      expire_after: 30
      availability:
        - topic: "rbgrid/<MAC>/status"
          payload_available: "online"
          payload_not_available: "offline"
      device:
        identifiers: ["<MAC>"]

Três pormenores aí não são decorativos.

Os modelos têm guarda, e têm de a ter. Os campos tarifários estão ausentes da trama até existir um plano no hub — e ligar o broker antes de introduzir uma tarifa é uma ordem de trabalho perfeitamente normal. Um value_json.system.tariff.zone sem guarda falha por causa da chave em falta, e o Home Assistant não regista nada: o MQTT engole os erros dos modelos em silêncio. Pior: o sensor volta a armar o expire_after antes de avaliar o modelo, por isso um hub sem plano mantém o sensor vivo no último valor indefinidamente — uma zona desatualizada que parece perfeitamente saudável. A versão com guarda reporta unknown, um estado que a sua automação pode recusar usar.

O segundo sensor é o preço atual, e está ali por uma razão que merece ser explicada. O painel de energia do Home Assistant pode receber uma entidade como preço atual de uma fonte, por isso o buy_rate do hub dá ao seu painel o valor correto para a zona em que está neste momento — e é assim que o custo é calculado do lado do Home Assistant, com a sua própria tarifa, para o que já tiver lá. O RBgrid guarda o dinheiro por circuito; o HA mantém a imagem da casa inteira que sempre teve.

plan_active é o seu único indicador. Como nada aparece no registo, esse atributo é a forma de ver se o hub tem de facto uma tarifa. Vale a pena pô-lo num painel se pretender confiar em alguma coisa disto.

default_entity_id fixa o id da entidade. As entidades MQTT tomam o id a partir do nome do dispositivo mais o nome da entidade; sem ele, este sensor ficaria em sensor.rbgrid_system_tariff_zone e todas as automações abaixo ficariam, em silêncio, a observar o vazio. (object_id fazia o mesmo trabalho e está obsoleto a partir do HA 2025.12.) O prefixo ha_ em unique_id mantém-no afastado do espaço de nomes do firmware, por isso, se uma versão futura descobrir ela própria uma entidade de zona, as duas coexistem e você elimina este bloco.

O expire_after: 30 continua a importar: a trama não é retida, por isso, se o hub ficar silencioso, o sensor passa a indisponível em vez de manter uma zona que pode já não ser verdadeira.

O tópico de disponibilidade também faz trabalho real: o hub publica online retido a cada ligação, e regista um last will MQTT para que o broker publique offline se ele cair sem se despedir. Um Home Assistant que reinicie fica, por isso, a saber o estado do hub imediatamente, em vez de esperar por uma trama. E se o seu broker reiniciar e perder as mensagens retidas, o hub volta a publicar todo o conjunto de descoberta quando se religar, para que as suas entidades de ponto não fiquem órfãs.

Uma armadilha antes de construir sobre isto. O time_src só lê sntp depois de o hub ter contactado um servidor NTP. Um relógio que definiu à mão a partir do navegador continua a indicar none, mesmo estando correto — por isso, num hub sem acesso à internet, a condição da secção seguinte nunca se verifica e a automação nunca dispara, em silêncio e para sempre. Se o time_src continuar em none, é isso que deve investigar: a rota do hub até um servidor de hora, e não a automação.

O sensor lê um de oito valores — NIGHT, MORNING_PEAK, DAY, EVENING_PEAK, LATE_EVENING, WEEKEND, HOLIDAY, CRITICAL_PEAK — escritos exatamente assim. É o tipo da zona ativa, e não o nome que lhe deu, por isso duas zonas de tipos diferentes ao mesmo preço continuam a ler-se de forma diferente. Sem plano tarifário no hub, o campo nem sequer está na trama, e o sensor com guarda lê unknown com plan_active: false.

Saberá que funciona quando o Developer Tools → States mostrar o novo sensor a ler um nome de zona como NIGHT, com plan_active: true, time_src: sntp e placeholder: false entre os seus atributos. Se ficar em unknown, o tópico ou o caminho do modelo está errado para o seu hub: subscreva rbgrid/# em qualquer cliente MQTT e compare uma trama real com o modelo.

Os atributos vêm por uma razão, e é mais afiada do que parece. O hub calcula a zona a partir do seu próprio relógio mesmo quando esse relógio ainda não está sincronizado — depois de um arranque sem SNTP, fica perto de 1970 mais o tempo de funcionamento, por isso a zona que reporta, e o preço que cobra, podem estar simplesmente errados. Não retém o campo enquanto espera. O time_src é a forma de o saber, e a secção seguinte recusa agir até ele ler sntp.

⚠️ Após qualquer reinício, volte a guardar a sua tarifa antes de confiar nestes valores — ou de os deixar acionar fosse o que fosse. Na v1.1.4, um hub que reinicia volta ao plano de exemplo incorporado Test Day/Night até abrir Tariffs e premir Save (o guia de tarifas tem o detalhe). O problema para este artigo: enquanto isso for verdade, a zona continua a ler um NIGHT perfeitamente plausível e o time_src continua a ler sntp, por isso a verificação da secção seguinte passa e a sua automação move a bomba de calor com base nos limites do plano de teste. Imagine um corte de energia às 02:00.

5. Automatizar — no Home Assistant, sobre o setpoint

O RBgrid mede e reporta. Não comuta nada: nem relé, nem contactor, nem saída de qualquer tipo. Tudo o que está abaixo corre do lado do Home Assistant, sobre uma entidade de clima que já tenha.

yaml
automation:
  - alias: "Heat pump: follow tariff zone (reconcile)"
    mode: single
    max_exceeded: silent
    triggers:
      - trigger: state
        entity_id: sensor.rbgrid_tariff_zone
        to: ~
      - trigger: state
        entity_id: sensor.rbgrid_tariff_zone
        attribute: placeholder
      - trigger: homeassistant
        event: start
      - trigger: time_pattern
        minutes: "/15"
    conditions:
      - condition: state
        entity_id: sensor.rbgrid_tariff_zone
        state: ["NIGHT", "DAY"]
      - condition: template
        value_template: "{{ state_attr('sensor.rbgrid_tariff_zone', 'time_src') == 'sntp' }}"
      - condition: template
        value_template: "{{ state_attr('sensor.rbgrid_tariff_zone', 'placeholder') is sameas false }}"
    actions:
      - variables:
          target: "{{ 21 if is_state('sensor.rbgrid_tariff_zone', 'NIGHT') else 19 }}"
      - condition: template
        value_template: "{{ (state_attr('climate.heat_pump', 'temperature') | float(0)) != (target | float) }}"
      - action: climate.set_temperature
        target: { entity_id: climate.heat_pump }
        data: { temperature: "{{ target }}" }
  - alias: "RBGrid: placeholder tariff plan active"
    mode: single
    triggers:
      - trigger: state
        entity_id: sensor.rbgrid_tariff_zone
        attribute: placeholder
        to: true
    actions:
      - action: persistent_notification.create
        data:
          notification_id: rbgrid_placeholder_plan
          title: "RBGrid: placeholder tariff plan"
          message: >-
            The hub is running the built-in Test Day/Night plan. Re-save your tariff
            plan in the RBgrid app; zone automations stay paused until then.

A guarda do plano de exemplo é a terceira condição, e é a que a maioria das pessoas não pensará em pôr. Um hub que reinicia na v1.1.4 volta ao plano incorporado Test Day/Night até voltar a guardar o seu — e, enquanto isso for verdade, a zona continua a ler-se de forma plausível e o relógio continua a dizer-se sincronizado, por isso todas as verificações óbvias passam. Agir com base nele acionaria a sua bomba de calor com preços de teste.

O hub diz isso, porém, se lhe perguntar: enquanto o plano incorporado estiver ativo, a telemetria traz placeholder: true, e a chave simplesmente deixa de aparecer depois de guardar o seu próprio plano. A condição é estrita de propósito — só age com um false explícito, nunca com um atributo em falta — por isso um sensor que não consegue dizer nada é tratado da mesma forma que um hub que está no plano de teste.

A segunda automação só serve para lhe dizer porque é que tudo ficou em silêncio. E, como a automação de reconciliação também dispara com esse atributo, no momento em que voltar a guardar o seu plano na aplicação o setpoint é atualizado de imediato, em vez de esperar pelo próximo quarto de hora.

Aponte isto para um termóstato de divisão, e verifique primeiro. O climate.set_temperature pressupõe uma entidade com um alvo de temperatura ambiente ajustável em °C. Muitas integrações de bombas de calor expõem outra coisa: uma temperatura de ida ou de água, uma curva de compensação meteorológica em que um alvo não faz nada, uma entidade só com predefinições sem temperatura ajustável — ou o depósito de água quente. Definir 21 numa entidade de temperatura de ida não é um empurrão; num depósito de AQS é um cilindro frio e um ciclo de legionella que não pretendia.

Abra o Developer Tools → States, encontre a sua entidade de clima e confirme que tem um atributo temperature no intervalo que espera antes de deixar seja o que for escrever nela.

Associe-a à automação espelho na zona de dia, definindo a temperatura um ou dois graus mais baixa, ou climate.set_preset_mode: eco se a sua unidade tiver esse modo.

Confirme que NIGHT é mesmo a sua zona barata. O sensor reporta o tipo da zona, não o nome que lhe deu, e é o tipo que decide o que acontece:

  • Se o seu plano tiver uma zona de Fim de semana, ela sobrepõe-se à da noite nos dias em que funciona, e WEEKEND não está na condição acima — por isso, a partir do momento em que essa zona começa, a automação deixa de decidir fosse o que fosse. Não recua para o alvo de dia: o setpoint mantém o que lhe foi dado por último, por isso, se a noite de sexta-feira definiu o alvo noturno, a casa mantém esse alvo até a zona de fim de semana terminar. Se isso lhe convém é uma questão sobre o seu preço de fim de semana, que o nome da zona não responde — veja abaixo.
  • Se a sua tarifa barata vier em duas janelas — uma noite barata e um meio-dia barato, o que serve bem uma bomba de calor —, a segunda chega como um tipo diferente, como LATE_EVENING, e precisa de um gatilho próprio. Duas janelas baratas num mesmo dia explica como se constrói um plano desse tipo.
  • Numa tarifa de três zonas, «a zona de dia» pode ser DAY, MORNING_PEAK ou EVENING_PEAK, e vai querer um gatilho para cada uma.

Observe o sensor durante um dia antes de confiar em qualquer valor to:.

Uma zona de fim de semana merece uma decisão, não um valor por defeito. WEEKEND é um tipo de zona; não diz nada sobre o que paga. Ponha o sensor Tariff Buy Rate da §4 num painel, observe-o num sábado e, depois, acrescente "WEEKEND" à lista state: para que a automação atue ao fim de semana em vez de passar em silêncio por ele. Para onde vai a partir daí é uma linha. Tal como está, o modelo target trata todas as zonas que não são NIGHT como alvo de dia, por isso um fim de semana a preço cheio recebe o setpoint de dia — o que é o pretendido. Acrescente or is_state('sensor.rbgrid_tariff_zone', 'WEEKEND') a essa linha e um fim de semana barato recebe o noturno:

yaml
conditions:
      - condition: state
        entity_id: sensor.rbgrid_tariff_zone
        state: ["NIGHT", "DAY", "WEEKEND"]            # add WEEKEND here → the automation also acts at weekends
    actions:
      - variables:
          # a full-price weekend: leave this line exactly as it is in the automation above — WEEKEND then gets 19
          # a cheap weekend: add the second is_state(), as below — WEEKEND then gets 21
          target: "{{ 21 if is_state('sensor.rbgrid_tariff_zone', 'NIGHT') or is_state('sensor.rbgrid_tariff_zone', 'WEEKEND') else 19 }}"

As duas formas foram executadas contra uma zona WEEKEND real e fazem exatamente isso; as guardas time_src e placeholder acima não foram alteradas e continuam a aplicar-se em qualquer dos casos. A automação atua em duas zonas por defeito porque o hub lhe pode dizer o tipo da zona e o seu preço, mas não qual delas o seu agregado familiar quer seguir.

Desligue primeiro qualquer horário que já corra nesta entidade. Se uma automação baseada no tempo e esta escreverem ambas o setpoint, vão entrar em conflito, e a que escrever por último ganha — o que não é uma propriedade que queira ver a decidir o seu aquecimento.

O hub volta a resolver a zona a cada três segundos e publica no seu próprio temporizador de três segundos, por isso uma mudança de zona aparece em cerca de seis segundos, no pior dos casos, normalmente antes, mais a latência do próprio Home Assistant. É suficientemente rápido para um setpoint; não construa nada que precise do limite ao segundo.

Converge; não reage. Isto é a parte que vale a pena perceber antes de a adaptar. Uma automação que só dispara na transição para uma zona tem uma falha que não vai notar: se o Home Assistant estiver a reiniciar, ou o broker tiver uma falha, ou o hub estiver silencioso quando passarem as 23:00, a transição perde-se e o setpoint nunca é reposto. A bomba fica no alvo de dia — e nada na casa lho diz, até fazer frio.

Por isso, o gatilho não é «começou a zona da noite», é «algo mudou, ou reiniciámos, ou passaram quinze minutos». A ação calcula então o que a zona atual exige e só o envia se a bomba de calor ainda não estiver lá. É idempotente, por isso correr após um reinício é o comportamento correto, e não algo a suprimir, e um limite perdido corrige-se sozinho no próximo quarto de hora, o mais tardar.

O que mantém isto seguro são as condições, não o gatilho: a zona tem de ser um valor real (unknown e unavailable ficam de fora), o relógio do hub tem de estar sincronizado e tem de ter confirmado o plano tarifário. Se qualquer uma falhar, nada é enviado e a bomba de calor continua a correr o seu próprio programa.

Empurre o setpoint; não controle a alimentação. Manter a bomba desligada até começar a zona barata é a ideia óbvia e a errada: os compressores precisam dos seus próprios ciclos, dos ciclos de descongelamento e dos ciclos anti-legionella.

A entrada de sinal da rede da própria unidade — SG Ready, na maior parte da Europa — pode bloqueá-la, incluindo um bloqueio total de até duas horas, e os contactos de bloqueio da concessionária são normais nas tarifas de bombas de calor. A diferença é que o controlador do fabricante continua a gerir o descongelamento e a legionella enquanto a bomba está bloqueada, e sabe quando se sobrepor. Uma ficha inteligente na linha de alimentação não gere nada disso. Por isso: o setpoint, um predefinido ou um modo, através da interface da própria unidade — nunca a alimentação.

Faça da «ausência de dados» o estado seguro — e saiba o que isso deixa para trás. Se o hub ficar offline, o sensor passa a indisponível, as condições falham e nada é enviado, por isso a bomba de calor segue o seu próprio programa. Esse é o comportamento certo para o equipamento.

Seja claro quanto ao que não é, porém: se a automação de dia já tiver baixado o seu setpoint, nada o repõe enquanto o hub estiver ausente. O silêncio protege a máquina, não o seu conforto. É precisamente por isso que o desenho de reconciliação importa — quando o hub voltar, o próximo ciclo põe o setpoint onde a zona atual diz que deve estar, sem que tenha de fazer nada.

Corra-a primeiro como notificação. Durante um ou dois dias, substitua a ação climate.set_temperature por

yaml
- action: persistent_notification.create
        data:
          title: "Tariff zone"
          message: "Would set the heat pump to {{ target }} °C"

e observe quando teria disparado. Não custa nada, e é assim que descobre que o limite da sua zona não está onde pensava — ou que a sua entidade de clima não é a que supunha.

Se não tiver uma entidade de clima no Home Assistant, salte esta secção por completo. A medição e a imagem do custo por zona aguentam-se sozinhas, e uma automação que não consegue conduzir bem é pior do que nenhuma.

O que isto não faz

  • O RBgrid nunca comuta nada. Não tem saídas. Cada ação deste guia é o Home Assistant a atuar sobre o seu próprio equipamento.
  • O custo por circuito fica na aplicação. O Home Assistant recebe a energia da bomba de calor, não o seu custo.
  • Sem custo por zona por período. A divisão por zona é um total acumulado desde o último reinício do hub.
  • O papel não é visível no HA, por isso uma automação não consegue distinguir um ponto de aquecimento de qualquer outro.
  • Um hub cujo relógio não sincronizou continua a reportar uma zona e a preçar a energia, a partir de qualquer hora que julgue ser. É por isso que a automação acima verifica o time_src, e por que os primeiros valores após um arranque a frio merecem uma segunda leitura.
  • O RBgrid mostra quanto custou a energia da bomba aos seus preços. Não confere a fatura do seu fornecedor e não faz nenhuma afirmação sobre quanto vai poupar.

Seguinte