Este tutorial traz a opção de utilizar o módulo PZEM-004T para realizar a medição de energia no Home Assistant.
É uma variante da opção de utilizar Tasmota.
Do que você irá precisar?
- Módulo PZEM004T - 100A
- NodeMcu v3
- Jumpers
- Fonte de alimentação para o nodemcu.
- Add-on ESPHOME instalado no home assistant (ESPHome no seu Home Assistant - ESPHome - Fórum Home Assistant Brasil).
Este tutorial não tem como objetivo mostrar como efetuar a ligação dos módulos PZEM à sua rede elétrica, para isso é altamente recomendado que você procure um profissional capacitado para intervir na sua rede elétrica e siga as instruções do manual.
Alterando os endereços dos módulos PZEM
Por padrão os módulos PZEM vem de fabrica com o endereço 1, para utilizar mais de um PZEM no mesmo nodemcu é necessário alterar esse endereço de forma a não repetir o endereço de nenhum PZEM.
Caso você for utilizar mais de um módulo no seu nodemcu, deverá realizar esta alteração se desejar usar apenas um pino digital. Caso contrário, pode prosseguir sem alterar.
Para alterar o endereço do módulo PZEM veja as alternativas:
Código para o ESPHome:
O código a seguir contém a estrutura necessária para a instalação de três módulos PZEM em um único nodemcu de forma a monitorar um quadro ou carga trifásica.
Crie um novo dispositivo no add-on ESPHome e substitua todo o código pelo código a seguir.
É necessário alterar apenas as primeiras linhas de configuração (você pode utilizar o arquivo secrets.yaml do ESPHome como sugerido ou colocar as informações no prório arquivo do código.
O código abaixo foi elaborado para que você necessite de poucas alterações, basta realizar as alterações a seguir.
- Alteração da Plataforma e Tipo da Placa se você não tiver usando um nodemcu baseado em esp8266.
- hostname: Nome do host na rede (será usado para o mDNS - não utilzar o caracter _ devido causar erro na resolução de nomes do mDNS).
- RedeWifi: Nome da rede wifi que o nodemcu irá se conectar.
- SenhaWifi: Senha da rede wifi que o nodemcu irá se conectar.
- SenhaWifiReconfig: Definição de uma senha para o wifi do nodemcu em caso de falha na conexão da rede configurada. Será usado para reconfiguração do mesmo via rede.
- EndConfig: Endereço que será feito upload do arquivo do esphome (o endereço IP atual do nodemcu na rede).
- SenhaAPI: Senha que será solicitada no Home Assistant para configurar a integração ESPHome
- PinoTX: Pino do nodemcu que será usado como TX para conexão dos módulos PZEM.
- PinoRX: Pino do nodemcu que será usado como RX para conexão dos módulos PZEM.
- NumFases: Número de fases (número de PZEM), de 1 a 3 que está sendo conectado ao nodemcu.
- TempoAtualizacao: Tempo de atualização das medições no Home Assistant.
Código:
substitutions:
#Configurações:
Plataforma: ESP8266
TipoPlaca: d1_mini
hostname: 'casaenergiatuto' #Hostname do dispositivo na rede (não usar underline '_' pois atrapalha o funcionamento do mDNS).
PrefixoNome: "Med.Energia - "
RedeWifi: !secret RedeWifi #Nome da rede wifi que o dispositivo irá se conectar
SenhaWifi: !secret SenhaWifi #Senha da rede wifi que o dispositivo irá se conectar
SenhaWifiReconfig: !secret SenhaWifiReconfig #Senha do AP Wifi para reconfiguração do wifi do dispositivo
EndConfig: ${hostname}.local #192.168.1.50 #Endereço para configuração (IP que o esp está acessível atualmente na rede), especialmente usado quando quer alterar o hostname via OTA
WifiOculto: 'False' #Se a rede wifi está oculta defina como 'True'
WifiFastConnect: 'False' #Se o esp realizará a conexão à rede wifi sem escanear as redes disponíveis defina como 'True'
SenhaAPI: !secret SenhaAPI #Senha para adicionar o esp no HA
SenhaOTA: !secret SenhaOTA #Senha para atualizar o firmware do esp via OTA
#Configuração da rede dos PZEMs
PinoTX: "GPIO5" #Pino TX que o PZEM está conectado no esp
PinoRX: "GPIO4" #Pino RX que o PZEM está conectado no esp
#Endereço do PZEM de cada fase
EndPZEMFase1: "1" #Endereço do módulo PZEM (padão de fábrica é 1)
EndPZEMFase2: "2" #Endereço do módulo PZEM (padão de fábrica é 1, neste caso alteramos para 2)
EndPZEMFase3: "3" #Endereço do módulo PZEM (padão de fábrica é 1, neste caso alteramos para 3)
#Configuração do sistema de medição:
NumFases: "3" #Número de fases presentes na medição (número de PZEM na rede)
TempoAtualizacao: "15s" #Tempo de atualização das medições no home assistant
esphome:
name: $hostname
comment: Medição de energia monofásica, bifásica ou trifásica com PZEM-004T-V3
platform: ${Plataforma}
board: ${TipoPlaca}
project:
name: "dougiteixeira.pzemgeral"
version: "1.0.0"
wifi:
networks:
- ssid: ${RedeWifi}
password: ${SenhaWifi}
hidden: ${WifiOculto}
fast_connect: ${WifiFastConnect}
use_address: ${EndConfig}
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: WIFI
password: ${SenhaWifiReconfig}
#Habilita um AP Wifi para reconfigurar em caso de perda de conexão com a rede configurada
captive_portal:
#Habilita a api para comunicar com o Home Assistant
api:
password: ${SenhaAPI}
#Habilita a atualização de firmware por OTA
ota:
password: ${SenhaOTA}
logger:
baud_rate: 0
#Configuração pinos PZEM
uart:
tx_pin: ${PinoTX}
rx_pin: ${PinoRX}
baud_rate: 9600
stop_bits: 1
parity: NONE
button:
#Comando reinicilizar esp remotamente
- platform: restart
id: restart_button
name: ${PrefixoNome} Reiniciar
icon: mdi:restart
text_sensor:
#Informações da conexão wifi
- platform: wifi_info
#Endereço IP
ip_address:
id: IP
name: ${PrefixoNome} Endereço IP
icon: mdi:ip-network
#Nome da Rede
ssid:
id: SSID
name: ${PrefixoNome} Rede Wifi
icon: mdi:wifi
#Informação da versão da compilação
- platform: version
id: versao
name: ${PrefixoNome} Versão
icon: mdi:information
binary_sensor:
#Status (conectado ou desconectado)
- platform: status
id: status_esp
name: ${PrefixoNome} Status
device_class: connectivity
sensor:
#Sensor Intensidade Sinal Wifi
- platform: wifi_signal
id: wifi_sinal
name: ${PrefixoNome} Intensidade Wifi
icon: mdi:signal
update_interval: 10s
#Sensores de energia da Fase 1
- platform: pzemac
current:
id: I1
name: "${PrefixoNome} Fase 1 - Corrente"
icon: mdi:current-ac
accuracy_decimals: 3
state_class: measurement
device_class: current
voltage:
id: V1
name: "${PrefixoNome} Fase 1 - Tensão"
icon: mdi:sine-wave
accuracy_decimals: 1
state_class: measurement
device_class: voltage
power:
id: P1
name: "${PrefixoNome} Fase 1 - Potência"
icon: mdi:flash
accuracy_decimals: 2
state_class: measurement
device_class: power
frequency:
id: F1
name: "${PrefixoNome} Fase 1 - Frequência"
icon: mdi:sine-wave
accuracy_decimals: 1
state_class: measurement
#device_class: frequency
power_factor:
id: FP1
name: "${PrefixoNome} Fase 1 - Fator de Potência"
icon: mdi:angle-acute
accuracy_decimals: 2
state_class: measurement
device_class: power_factor
energy:
id: E1
name: "${PrefixoNome} Fase 1 - Energia"
icon: mdi:counter
accuracy_decimals: 2
unit_of_measurement: kWh
state_class: total_increasing
device_class: energy
filters:
- multiply: 0.001
update_interval: ${TempoAtualizacao}
address: ${EndPZEMFase1}
#Sensores de energia da Fase 2
- platform: pzemac
current:
id: I2
name: "${PrefixoNome} Fase 2 - Corrente"
icon: mdi:current-ac
accuracy_decimals: 3
state_class: measurement
device_class: current
voltage:
id: V2
name: "${PrefixoNome} Fase 2 - Tensão"
icon: mdi:sine-wave
accuracy_decimals: 1
state_class: measurement
device_class: voltage
power:
id: P2
name: "${PrefixoNome} Fase 2 - Potência"
icon: mdi:flash
accuracy_decimals: 1
state_class: measurement
device_class: power
frequency:
id: F2
name: "${PrefixoNome} Fase 2 - Frequência"
icon: mdi:sine-wave
accuracy_decimals: 1
state_class: measurement
#device_class: frequnecy
power_factor:
id: FP2
name: "${PrefixoNome} Fase 2 - Fator de Potência"
icon: mdi:angle-acute
accuracy_decimals: 2
state_class: measurement
device_class: power_factor
energy:
id: E2
name: "${PrefixoNome} Fase 2 - Energia"
icon: mdi:counter
accuracy_decimals: 2
unit_of_measurement: kWh
state_class: total_increasing
device_class: energy
filters:
- multiply: 0.001
update_interval: ${TempoAtualizacao}
address: ${EndPZEMFase2}
#Sensores de energia da Fase 3
- platform: pzemac
current:
id: I3
name: "${PrefixoNome} Fase 3 - Corrente"
icon: mdi:current-ac
accuracy_decimals: 3
state_class: measurement
device_class: current
voltage:
id: V3
name: "${PrefixoNome} Fase 3 - Tensão"
icon: mdi:sine-wave
accuracy_decimals: 1
state_class: measurement
device_class: voltage
power:
id: P3
name: "${PrefixoNome} Fase 3 - Potência"
icon: mdi:flash
accuracy_decimals: 1
state_class: measurement
device_class: power
frequency:
id: F3
name: "${PrefixoNome} Fase 3 - Frequência"
icon: mdi:sine-wave
accuracy_decimals: 1
state_class: measurement
#device_class: frequnecy
power_factor:
id: FP3
name: "${PrefixoNome} Fase 3 - Fator de Potência"
icon: mdi:angle-acute
accuracy_decimals: 2
state_class: measurement
device_class: power_factor
energy:
id: E3
name: "${PrefixoNome} Fase 3 - Energia"
icon: mdi:counter
accuracy_decimals: 2
unit_of_measurement: kWh
state_class: total_increasing
device_class: energy
filters:
- multiply: 0.001
update_interval: ${TempoAtualizacao}
address: ${EndPZEMFase3}
#Potência Aparente Fase 1
- platform: template
id: S1
name: "${PrefixoNome} Fase 1 - Potência Aparente"
icon: mdi:alpha-s
accuracy_decimals: 1
lambda: |-
return id(I1).state * id(V1).state;
unit_of_measurement: "VA"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: apparent_power
#Potência Reativa Fase 1
- platform: template
id: Q1
name: "${PrefixoNome} Fase 1 - Potência Reativa"
icon: mdi:alpha-q
accuracy_decimals: 1
lambda: |-
return id(S1).state * sin(acos(id(FP1).state));
unit_of_measurement: "var"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: reactive_power
#Potência Aparente Fase 2
- platform: template
id: S2
name: "${PrefixoNome} Fase 2 - Potência Aparente"
icon: mdi:alpha-s
accuracy_decimals: 1
lambda: |-
return id(I2).state * id(V2).state;
unit_of_measurement: "VA"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: apparent_power
#Potência Reativa Fase 2
- platform: template
id: Q2
name: "${PrefixoNome} Fase 2 - Potência Reativa"
icon: mdi:alpha-q
accuracy_decimals: 1
lambda: |-
return id(S2).state * sin(acos(id(FP2).state));
unit_of_measurement: "var"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: reactive_power
#Potência Aparente Fase 3
- platform: template
id: S3
name: "${PrefixoNome} Fase 3 - Potência Aparente"
icon: mdi:alpha-s
accuracy_decimals: 1
lambda: |-
return id(I3).state * id(V3).state;
unit_of_measurement: "VA"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: apparent_power
#Potência Reativa Fase 3
- platform: template
id: Q3
name: "${PrefixoNome} Fase 3 - Potência Reativa"
icon: mdi:alpha-q
accuracy_decimals: 1
lambda: |-
return id(S3).state * sin(acos(id(FP3).state));
unit_of_measurement: "var"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: reactive_power
#Potência Ativa Total
- platform: template
id: PT
name: "${PrefixoNome} Potência Ativa Total"
icon: mdi:flash
accuracy_decimals: 1
lambda: |-
if (${NumFases}==1) {
return id(P1).state;
}
if (${NumFases}==2) {
return id(P1).state + id(P2).state;
}
if (${NumFases}==3) {
return id(P1).state + id(P2).state + id(P3).state;
}
unit_of_measurement: "W"
update_interval: ${TempoAtualizacao}
state_class: measurement
device_class: power
#Potência Aparente Total
- platform: template
id: ST
name: "${PrefixoNome} Potência Aparente Total"
icon: mdi:alpha-s
accuracy_decimals: 1
lambda: |-
if (${NumFases}==1) {
return id(S1).state;
}
if (${NumFases}==2) {
return id(S1).state + id(S2).state;
}
if (${NumFases}==3) {
return id(S1).state + id(S2).state + id(S3).state;
}
unit_of_measurement: "VA"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: apparent_power
#Potência Reativa Total
- platform: template
id: QT
name: "${PrefixoNome} Potência Reativa Total"
icon: mdi:alpha-q
accuracy_decimals: 1
lambda: |-
if (${NumFases}==1) {
return id(Q1).state;
}
if (${NumFases}==2) {
return id(Q1).state + id(Q2).state;
}
if (${NumFases}==3) {
return id(Q1).state + id(Q2).state + id(Q3).state;
}
unit_of_measurement: "var"
update_interval: ${TempoAtualizacao}
state_class: measurement
#device_class: reactive_power
#Fator de Potência Total
- platform: template
id: FPT
name: "${PrefixoNome} Fator de Potência Total"
icon: mdi:angle-acute
accuracy_decimals: 2
lambda: |-
return id(PT).state / id(ST).state;
unit_of_measurement: ""
update_interval: ${TempoAtualizacao}
state_class: measurement
device_class: power_factor
#Energia Total
- platform: template
id: ET
name: "${PrefixoNome} Energia Total"
icon: 'mdi:counter'
accuracy_decimals: 3
lambda: |-
if (${NumFases}==1) {
return (id(E1).state);
}
if (${NumFases}==2) {
return (id(E1).state + id(E2).state);
}
if (${NumFases}==3) {
return (id(E1).state + id(E2).state + id(E3).state);
}
unit_of_measurement: "kWh"
update_interval: ${TempoAtualizacao}
state_class: total_increasing
device_class: energy
Todas essas informações importantes (senhas OTA e API, configuração da rede wifi, etc) estão armazenadas no arquivo secrets.yaml
(ver aqui e aqui para mais detalhes de configuração e uso).
Enviando o código para o nodemcu:
O primeiro envio do código para o nodemcu deve ser realizado via USB, para isso clique em nos três pontos () do dispositivo no add-on ESPHome e em Install:
E clique em Manual download e selecione a opção Legacy format:
O código será compilado e ao final será exibido o será feito o download do arquivo do firmware.
Após fazer upload do código para o nodemcu, as próximas atualizações podem ser realizadas via rede (OTA), bastando clicar na opção Wirelessly ao instalar:
Adicionado o dispositivo no Home Assistant.
Navegue para Configurações > Integração > Adicionar Integração e pesquise a integração ESPHome na lista:
Informe o endereço IP ou nome do host do dispositivo e clique em Enviar:
Informe a senha da API configurada no código do ESPHome e clique em enviar:
O dispositivo adicionado será exibido.
Adicionando a entidade Energia Total no painel de energia do Home Assistant:
Navegue para Configurações > Energia e adicione a entidade Energia Total ao Grid consumption
:
Após um período de algumas horas será possível visualizar o gráfico de consumo no painel de energia:
Estatísticas utility meter
:
As entidades utility meter
podem ser criadas normalmente a partir da informação de energia totoal e vão servir para estatística para o usuário, podendo ser usadas em automação.
O código para criar as entidades utility meter é:
#Totalizado com reset diário
energia_diaria:
source: sensor.med_energia_energia_total
cycle: daily
tariffs:
- normal
#Totalizado com reset semanal
energia_semanal:
source: sensor.med_energia_energia_total
cycle: weekly
tariffs:
- normal
#Totalizado com reset mensal
energia_mensal:
source: sensor.med_energia_energia_total
cycle: monthly
tariffs:
- normal
#Totalizado com reset anual
energia_anual:
source: sensor.med_energia_energia_total
cycle: yearly
tariffs:
- normal
#Totalizado sem reset periódico
energia_total:
source: sensor.med_energia_energia_total
tariffs:
- normal