Preço do kwh e bandeira tarifaria

Cara, pode compartilhar mais info de como q vc construiu os valores dos sensores? Só pra entender tbm, vc está fazendo OCR com quais dados?

Ola Vinicius ,
Desculpe a demora para responder , eu configurei o site para enviar email de notificação , mas não veio nada.
Vi por acaso a sua questão agora.

Bom , abaixo escrevi na sequencia que achei mais logica .
O que foi mais dificil de descobrir para aplicar foi a regra do PIS/COFINS e ICMS , é um calculo “maldito” .
Achei ele de forma clara no site outra distribuidora.

Buscar dados da WEB

A unica exceção foi o ICMS , que desde sempre é 18% em SP , então não me dei ao trabalho de buscar de alguma fonte oficial.

Este é o primeiro script que coleta tarifas e bandeira.

# by Cesar Martins - 2025-01-09
#
#
# https://dadosabertos.aneel.gov.br/dataset/tarifas-distribuidoras-energia-eletrica
#
# BUSCA PERSONALIZADA COM OS FILTROS
# https://dadosabertos.aneel.gov.br/dataset/tarifas-distribuidoras-energia-eletrica/resource/fcf2906c-7c32-4b9b-a637-054e7a5234f4?filters=SigAgente%3ACPFL-PIRATINING%7CDscSubGrupo%3AB1%7CDscSubClasse%3AResidencial%7CDscClasse%3AResidencial%7CDscModalidadeTarifaria%3AConvencional%7CDscBaseTarifaria%3ATarifa%20de%20Aplica%C3%A7%C3%A3o%7CDscDetalhe%3AN%C3%A3o%20se%20aplica
#

_baixar_dados(){

# busca dados
Resource=fcf2906c-7c32-4b9b-a637-054e7a5234f4
SigAgente=CPFL-PIRATINING
SubGrupo=B1
Classe=Residencial
SubClasse=Residencial
ModalidadeT=Convencional
BaseT='Tarifa de Aplicação'
Detalhe='%aplica%' #nao se aplica

curl --silent -G "https://dadosabertos.aneel.gov.br/api/3/action/datastore_search_sql" --data-urlencode 'sql=SELECT
_id
--,DatGeracaoConjuntoDados
--,DscREH
,a."SigAgente"
,a."NumCNPJDistribuidora"
,a."DatInicioVigencia"
,a."DatFimVigencia"
,a."DscBaseTarifaria"
,a."DscSubGrupo"
,a."DscModalidadeTarifaria"
,a."DscClasse"
,a."DscSubClasse"
,a."DscDetalhe"
,a."NomPostoTarifario"
,a."DscUnidadeTerciaria"
,a."SigAgenteAcessante"
,a."VlrTUSD"
,a."VlrTE"
FROM "'"$Resource"'" as a
WHERE a."SigAgente" = '\'"$SigAgente"\''
AND a."DscSubGrupo" = '\'"$SubGrupo"\''
AND a."DscClasse" = '\'"$Classe"\''
AND a."DscSubClasse" = '\'"$SubClasse"\''
and a."DscModalidadeTarifaria" = '\'"$ModalidadeT"\''
and a."DscBaseTarifaria" = '\'"$BaseT"\''
and a."DscDetalhe" like '\'"$Detalhe"\''
order by "DatInicioVigencia" desc
' > cpfl_tarifas.out
[ $? -ne 0 ] && exit 1

#
# Converte output em csv , comando gerado por IA.
cat cpfl_tarifas.out | jq '.result.records' | jq -r '(map(keys) | add | unique) as $cols | map(. as $row | $cols | map($row[.])) as $rows | $cols, $rows[] | @csv' > cpfl_tarifas.csv


# BANDEIRA TARIFARIA
# https://dadosabertos.aneel.gov.br/dataset/bandeiras-tarifarias
# https://dadosabertos.aneel.gov.br/dataset/bandeiras-tarifarias/resource/0591b8f6-fe54-437b-b72b-1aa2efd46e42

Resource=0591b8f6-fe54-437b-b72b-1aa2efd46e42
curl --silent -G "https://dadosabertos.aneel.gov.br/api/3/action/datastore_search_sql" --data-urlencode 'sql=SELECT "DatCompetencia", "NomBandeiraAcionada", "VlrAdicionalBandeira"
FROM "'"$Resource"'"
ORDER BY "DatCompetencia" DESC
'  > bandeira.out

cat bandeira.out | jq '.result.records' | jq -r '(map(keys) | add | unique) as $cols | map(. as $row | $cols | map($row[.])) as $rows | $cols, $rows[] | @csv' > bandeira.csv
}

_show_valores()  {
vFiltro=$1
# busca abaixo, traz os valores dentro da vigencia, vigencias futuras nao sao exibidas...
vD=$(date +%Y-%m-%d)
vOut=$(
  # valores do TE e TUSD
  awk '{gsub(/","?/,";") ; gsub(/"/,"") ; print }'  cpfl_tarifas.csv  | tail -n +2 | \
    awk -v D="$vD" -F";" 'D >= $2 { print ; exit ;}'  | \
    awk -F';' '{printf "vVigenciaIni=%s\nvVigenciaFim=%s\nvTE=%s\nvTUSD=%s\n",$2,$1,$14,$15}'

  # Informacoes da bandeira
  awk '{gsub(/","?/,";") ; gsub(/"/,"") ; print }'  bandeira.csv  | \
    awk -v D="$vD" -F";" '$1 <= D { print ; exit ;}'  | \
    awk -F';' '{
      gsub(/^,/,"0,",$3)
      printf "vInicioBand=%s\nvBandeira=%s\nvValorBandeira=%s\n",$1,$2,$3}'
)
  {
  if [ "$vFiltro" != "-" ]; then
    echo "$vOut" | awk -v IGNORECASE=1 -v F=$vFiltro -F= '$1 ~ F { print $2}'
  else
    echo "$vOut"
  fi
  } | tr "," "."
}

cd $(dirname $0)
while getopts :bs: vOpcao
do
  case $vOpcao in
   b) _baixar_dados ;;
   s) _show_valores $OPTARG ;;
  esac
done

Exemplo de como usar:

# bash cpfl.tarifas.sh  -b

# bash cpfl.tarifas.sh  -s -
vVigenciaIni=2026-01-01
vVigenciaFim=2026-10-22
vTE=344.05
vTUSD=395.64
vInicioBand=2026-02-01
vBandeira=Verde
vValorBandeira=0.00

# bash cpfl.tarifas.sh  -s vTE
344.05

Para o PIS e COFINS

Este é outro script para PIS e COFINS , pois eles “andam juntos” nas divulgações.
Tem algumas tratativas de SSH ai porque como eu rodo meu HA em docker , a nova versão (ultima versão) não era mais possível rodar diretamente dentro do docker por causa do comando tesseract de OCR .
Então fiz ajustes para ele executar “remotamente” no host linux local via ssh.

#
# https://www.cpfl.com.br/piratininga/pis-cofins
#
# em out/2025 a cpfl mudou o site , o que antes era uma tabela passou a ser uma imagem que vem com javascript
#   foi necessario refazer todo o script, fazer OCR da imagem...
#   como utiliza comandos novos, nao da mais para executar direto no container.
#   Entao troquei o esquema para fazer um ssh para o host
#
cd $(dirname $0)

set -euo pipefail
  # -e exit quando qq comando falhar
  # -u falha se acessar variaveis nao inicializadas
  # -o pipefail falha se qualquer comando em um cmd1 | cmd2 | cmd3 falhar..
  #    CUIDADO: no ambiente docker , este parametro falha o script com erro 141 no "| head -n1" .
  #             porque o head -n1 fecha o pipe enquanto recebe dados .
  #             no caso contornei no awk com NR==1
shopt -s nocasematch
  # para uso do [[ ]]

vTmp=tmp.$(basename $0 .sh).$$
touch $vTmp # apenas para evitar codigo de exit errado no trap
trap "rm ${vTmp}* 2>/dev/null ; exit " 0 1 2

## versao 2 , funcionou ate set/2025 ai eles mudaram o site , onde a tabela passou a ser uma imagem.
_baixar_dados2() {
  # Extrai imagens e OCR das tabelas PIS e COFINS da CPFL Piratininga.
  #
  # 2025-10-19
  # Este script foi criado pelo ChatGPT
  # Porem readaptei o script original para funcionar aqui dentro...
  # https://chatgpt.com/share/68f54090-27d0-8001-95dc-77d7a339fd01
  BASE_URL="https://www.cpfl.com.br"
  PAGE_PATH="/piratininga/pis-cofins"
  TMPDIR=.
  UA="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36"
  vTmpPage=$vTmp.page.html
  vTmpLinks=$vTmp.links.txt
  echo "🔍 Baixando HTML da página..."
  curl -sSL -A "$UA" "${BASE_URL}${PAGE_PATH}" -o "$vTmpPage"
  echo "🔎 Procurando imagens de tarifas (PIS/COFINS)..."
  grep -Eoi '<img[^>]+src="[^"]+"' "$vTmpPage" \
    | sed -E 's/.*src="([^"]+)".*/\1/' \
    | grep -Ei 'pis|cofins' \
    | sed -E "s#^/#${BASE_URL}/#" \
    | sed -E "s#//#/#g" \
    | sort -u > "$vTmpLinks"
  if [ ! -s "$vTmpLinks" ]; then
    echo "❌ Nenhuma imagem encontrada com nomes contendo 'PIS' ou 'COFINS'."
    exit 1
  fi
  echo "🖼️ Imagens encontradas:"
  cat "$vTmpLinks"
  echo
  for LINK in $(cat "$vTmpLinks"); do
    NAME=$(basename "$LINK" | sed 's/%20/_/g')
    OUTIMG="$NAME"
    OUTTXT="${OUTIMG%.png}.txt"
    [[ $NAME =~ pis ]]  && OUTTXT=pis.txt
    [[ $NAME =~ cofins ]]  && OUTTXT=cofins.txt
    echo "⬇️  Baixando $NAME..."
    curl -sSL -A "$UA" -o "$OUTIMG" "$LINK"
    if command -v convert >/dev/null 2>&1; then
      echo "🧹 Limpando imagem antes do OCR (convert)..."
      convert "$OUTIMG" -colorspace Gray -contrast-stretch 1%x1% "$OUTIMG"
    fi
    echo "🔤 Rodando OCR (tesseract)..."
    # tesseract "$OUTIMG" "${OUTTXT%.txt}" -l por --psm 6 --oem 1 --dpi 300 -c preserve_interword_spaces=1 >/dev/null # 2>&1
    tesseract "$OUTIMG" "${OUTTXT%.txt}" -l por --psm 6 >/dev/null 2>&1
    echo "📝 Texto salvo em: $OUTTXT"
    echo
  done
  echo "✅ Extração concluída."
}

_corrige_tab(){
  grep -aiEh -A10 "$1" pis.txt cofins.txt | awk '
    function _converte(s){ split(s,d,"/"); printf "%s-%s-%s ",d[3],d[2],d[1] } ;
    $1 ~ "../../...." {
     printf "%s %s %s\n" , _converte($1),_converte($2),$3
  }
  '
}
_pega_valor(){
  awk -v d=$1 ' d >= $1 && d <= $2  { print $3} '
}
##########################
## feito para funcionar com a versao 1
_show_valores2(){
  vFiltro=$1
  d=$(date +%Y-%m-%d)
  vPIS=$(_corrige_tab "Tarifa(_| *)PIS"  | _pega_valor $d)
  vCOFINS=$(_corrige_tab "Tarifa(_| *)COFINS" | _pega_valor $d)

  # se valor do periodo nao existe, usa o ultimp disponivel...
  [ -z "$vPIS" ] && vPIS=$(_corrige_tab "Tarifa(_| *)PIS"| awk 'NR==1 {print $3}' )
  # se valor do periodo nao existe, usa o ultimp disponivel...
  [ -z "$vCOFINS" ] && vCOFINS=$(_corrige_tab "Tarifa(_| *)COFINS"| awk 'NR==1 {print $3}' )
  vOut=$(
    echo "vPIS="$vPIS
    echo "vCOFINS="$vCOFINS
  )
  {
  if [ "$vFiltro" != "-" ]; then
    echo "$vOut" | awk -v IGNORECASE=1 -v F=$vFiltro -F= '$1 ~ F { print $2}'
  else
    echo "$vOut"
  fi
  } | tr "," "." | tr -d "%"
}


#-# ##########################
#-# ## versao 1 , funcionou ate set/2025 ai eles mudaram o site , onde a tabela passou a ser uma imagem.
#-# _baixar_dados() {
#-# curl -s https://www.cpfl.com.br/piratininga/pis-cofins  > pis_cofins.html
#-# [ $? -ne 0 ] && exit 1
#-# html2text -ascii pis_cofins.html > pis_cofins.txt
#-# }
#-#
#-# ##########################
#-# ## feito para funcionar com a versao 1
#-# _show_valores1(){
#-#   vFiltro=$1
#-#   d=$(date +%Y-%m-%d)
#-#   vPIS=$(_corrige_tab "Tarifa_PIS"  | _pega_valor $d)
#-#   vCOFINS=$(_corrige_tab "Tarifa_COFINS" | _pega_valor $d)
#-#
#-#   # se valor do periodo nao existe, usa o ultimp disponivel...
#-#   [ -z "$vPIS" ] && vPIS=$(_corrige_tab "Tarifa_PIS"| head -n1 | awk '{print $3}' )
#-#   # se valor do periodo nao existe, usa o ultimp disponivel...
#-#   [ -z "$vCOFINS" ] && vCOFINS=$(_corrige_tab "Tarifa_COFINS"| head -n1 | awk '{print $3}' )
#-#   vOut=$(
#-#     echo "vPIS="$vPIS
#-#     echo "vCOFINS="$vCOFINS
#-#   )
#-#   {
#-#   if [ "$vFiltro" != "-" ]; then
#-#     echo "$vOut" | awk -v IGNORECASE=1 -v F=$vFiltro -F= '$1 ~ F { print $2}'
#-#   else
#-#     echo "$vOut"
#-#   fi
#-#   } | tr "," "." | tr -d "%"
#-# }


#
# Modo remoto!
#   ssh-keygen -t rsa -b 4096 -f docker_ssh_key -N ""
#   cat docker_ssh_key.pub  >> ~/.ssh/authorized_keys
#
if [[ $1 == -r ]]; then
  shift
  vCmd="~/ha.git/cpfl.tarifas/$( basename $0 ) $@ "
  chmod 400 $(dirname $0)/docker_ssh_key
  ssh -i $(dirname $0)/docker_ssh_key -o StrictHostKeyChecking=no root@box "$vCmd"
  exit
fi

while getopts :bs: vOpcao
do
  case $vOpcao in
   b) _baixar_dados2 ;;
   s) _show_valores2 $OPTARG ;;
  esac
done

Ler dados

Utilizo a integração command_line para executar o script shell e capturar os dados de cada coleta.

##### CPFL - atualizacao online dos valores de tarifa 
- sensor:
    name: CPFL Tarifa Vigencia Inicio
    unique_id: cpfl_tarifa_vigencia_inicio
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s VigenciaIni '
    scan_interval: 86400

- sensor:
    name: CPFL Tarifa Vigencia Fim
    unique_id: cpfl_tarifa_vigencia_fim
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s Vigenciafim '
    scan_interval: 86400

- sensor: 
    name: CPFL Tarifa Valor TE
    unique_id: cpfl_tarifa_valor_te
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s TE '
    device_class: monetary
    unit_of_measurement: "R$"
    scan_interval: 3600

- sensor: 
    name: CPFL Tarifa Valor USD
    unique_id: cpfl_tarifa_valor_usd
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s USD '
    device_class: monetary
    unit_of_measurement: "R$"
    scan_interval: 3600

- sensor: 
    name: CPFL Bandeira atual
    unique_id: cpfl_bandeira_atual
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s vBandeira '
    scan_interval: 3600

- sensor: 
    name: CPFL Bandeira atual Inicio
    unique_id: cpfl_bandeira_atual_inicio
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s vInicioBand '
    scan_interval: 3600

- sensor: 
    name: CPFL Bandeira atual Valor
    unique_id: cpfl_bandeira_atual_valor
    command: 'bash /config/root.bin/ha/cpfl.tarifas/cpfl.tarifas.sh -s ValorBand '
    device_class: monetary
    unit_of_measurement: "R$"
    scan_interval: 3600

- sensor: 
    name: "CPFL % PIS"
    unique_id: cpfl_pis
    command: 'bash /config/root.bin/ha/cpfl.tarifas/pis.cofins.sh -s PIS '
    device_class: monetary
    unit_of_measurement: "%"
    scan_interval: 3600

- sensor: 
    name: "CPFL % COFINS"
    unique_id: cpfl_cofins
    command: 'bash /config/root.bin/ha/cpfl.tarifas/pis.cofins.sh -s COFINS '
    device_class: monetary
    unit_of_measurement: "%"
    scan_interval: 3600

# ICMS , nao pesquisei onde buscar, mas basicamente eh sempre 18%...
- sensor: 
    name: "CPFL % ICMS"
    unique_id: cpfl_icms
    command: 'echo 18'
    device_class: monetary
    unit_of_measurement: "%"
    scan_interval: 3600

Carrego eles através de crontab

Antes tudo ficava em automação dentro do HA.
Com a mudança do site da CPFL tive que readaptar.
Então 1o faço o download dos dados as 3h da manhã, via crontab no host linux :

0 3  *  *  *  { cd ~/ha/root.bin/ha/cpfl.tarifas ; bash pis.cofins.sh -b ; bash cpfl.tarifas.sh -b ; }

E os sensores já tem o parametro scan_interval que se atualizam automaticamente, não preciso configurar mais nada.

Calculos

Como template, criei os sensores abaixo para somar corretamente os tributos.

- sensor:
    - name: Custo Energia CPFL 
      unique_id: custo_energia_cpfl
      unit_of_measurement: "R$/kWh"
      state: > 
        {{ ( 
           ( states("sensor.cpfl_tarifa_valor_te")|float(0)  
         + states("sensor.cpfl_tarifa_valor_usd")|float(0)  ) / 1000
         ) | round(4)
        }}

- sensor:
    - name: Custo Energia CPFL com tributos
      unique_id: custo_energia_cpfl_com_tributos
      unit_of_measurement: "R$/kWh"
# Sobre bandeiras...
# https://atosoficiais.com.br/aneel/resolucao-homologatoria-n-3306-2024-estabelece-as-faixas-de-acionamento-e-os-adicionais-das-bandeiras-tarifarias-de-que-trata-o-submodulo-6-8-do-proret-com-vigencia-a-partir-de-abril-de-2024
# 
# Regra para calculo do tributo (fonte: https://energes.com.br/entendendo-a-fatura-de-energia-3/ )
# (tarifa) / ((1-ICMS%)*(1-(PIS%+COFINS%)))
      state: > 
        {{ (
            (
              (states("sensor.custo_energia_cpfl")|float(0)) 
              / ( (1-(  (states('sensor.cpfl_icms')|float)/100)  )
                * (1-( ( states('sensor.cpfl_pis')|float  +  states('sensor.cpfl_cofins')|float )  /100) )
                )
            )
            + ((states('sensor.cpfl_bandeira_atual_valor')|float) / 1000)
           ) |round(4)
        }}

Então, também, como template , faço o calculo de custos.
Neste caso, eu tenho outros sensores acumuladores de potencia (Watts) que vem do meu device de monitor de consumo de energia da minha casa (Medição de Energia com Medidor TOMZN DTS238 + LocalTuya - #30 de ceinmart) .

Usando as integrações “Riemann sum” para acumular corretamente o consumo e utility_meter para quebrar isso em dias / semanas / mes , então eu tenho os consumos e os custos em tempo real.
Não só para a energia da casa , mas também para cada dispositivo que eu instalei uma tomada inteligente como geladeria, tv, pressurizadores, ar-condicionado (neste caso o aparelho já fornece o consumo), maquina de lavar roupa, maquina de lavar louça…

Valores totalizadores por dia , semana e mês.
(no caso, mês , eu considero o dia 24 de cada mês , pq é o dia que a CPFL sempre passa para fazer a leitura aqui em casa) .

energia_consumo_casa_diario:
  source: sensor.energia_consumida_acumulada_casa
  name: Energia consumo casa diario
  unique_id: 88f4a2ce-99e6-11ee-ae3d-56135b517a8f
  cron: "0 00 * * *"
energia_consumo_casa_semanal:
  source: sensor.energia_consumida_acumulada_casa
  name: Energia consumo casa semanal
  unique_id: a1a1e570-99e6-11ee-bbb8-56135b517a8f
  cron: "0 00 * * MON"
energia_consumo_casa_mensal_cpfl:
  source: sensor.energia_consumida_acumulada_casa
  name: Energia consumo casa mensal CPFL
  unique_id: b30f386c-99e6-11ee-8f56-56135b517a8f
  cron: "0 00 24 * *"

Calculo do consumo W x custo em R$

- sensor:
    - name: Energia consumo - casa - diario - cpfl custo
      unit_of_measurement: "R$"
      state: >
         {% set consumo = states('sensor.energia_consumo_casa_diario') | float %}
         {% set tarifa = states('sensor.custo_energia_cpfl_com_tributos') | float %}
         {% set valor = ( consumo * tarifa ) | round(2) %}
         {{ valor }}

Aqui , vai perceber que estou “duplicando” parte da logica do painel Energy nativo do HA.
Quando implementei isso, ele era limitado, tinha menos recursos e visualizações limitadas.
Por isso fiz o meu controle eo meu proprio dashboard de controle de energia.

Bom, talvez não tenha compartilhado aqui 100% do codigo, mas o grosso acho que dá para entender e dar uma iniciativa para construir o seu .

Eu diria que para simplificar, não precisaria do sensor “Riemann sum” (porque normalmente os dispositivos já vem com os acumuladores), eu usei porque muitos dos sensores que eu tinha não possuiam o totalizadores de potencia, hoje já possuem (recurso adicionado pelo TuyaLocal , salvo engano).

O utility_meter, considero necessário para conseguir ter o controle nos periodos de interesse.
Não sei se tem outra forma, mais simplificada, de fazer tudo isso que fiz.
Na época foi como conseguir dar de solução.

1 curtida

Bom dia pessoal!!

Para quem teve problema na inicialização do addon após a atualização do core para a versão 2026.3.0, já está disponível o hotfix 1.0.3.

Eu havia atualizado, mas acabei não reparando que a extensão não subiu.

Agradecimentos ao @Felps por enviar o PR com a correção.

Bom dia pessoal!!

Sempre são grandes emoções com a API da ANEEL quando o final do mês se aproxima. Quem teve problema na inicialização do addon ontem, já está disponível o hotfix 1.0.4.

Agradecimentos ao @Felps por enviar o PR com mais uma correção.

1 curtida

Bom dia pessoal!

Só para alertar a todos os usuários da integração. A fonte de dados das bandeiras tarifárias não está retornando dados desde o início da semana. Já abri um protocolo com eles para verificarem. Com este último fix, a integração não quebrará, mas pegará um valor default. Assim que tiver um posicionamento, aviso por aqui.

Abraço! o/

2 curtidas

Bom dia pessoal!

Disponibilizei a versão 1.1.0-beta.1 do addon com uma refatoração em alguns pontos, incluindo esta parte da aquisição da bandeira tarifária. Enquanto a ANEEL não responde sobre a API, notei que o arquivo CSV está completo, então adicionei o pré-carregamento do CSV ao subir a extensão e assim já mantém atualizado a bandeira tarifária atual. O fallback acabou ficando todo no banco de dados agora.

Já estou trabalhando para os próximos releases a exibição separada dos componentes tarifários. Estou estudando como farei a parte dos impostos e dos créditos de retorno para quem utiliza energia solar.

Se tiverem mais sugestões ou quiserem trocar mais idéias, é só chamar!

Abraço e boa páscoa!

3 curtidas

Ola @vodikus ,

É , eu tive esse problema com o acesso da API da ANEEL e também resolvi baixando o CSV, o complicado é que alguns CSVs são enormes para ficar baixando com frequencia.

Gostaria de abandonar meus scripts e usar sua extensão, mas ai precisamos de mais dados.
No caso , eu estou fazendo cálculos também para a minha Fotovoltaica.

Quais tarifas sua extensão consegue disponibilizar hoje?
O chato é saber encontrar os dados, por exemplo, taxa do fio b de 2026 está no arquivo de 2025… porque eles colocam pela data de quando sai a Lei e não pela vigencia.

As informações que precisaria :

Que é possivel pegar no site da ANEEL
No meu caso para CPFL PIRATININGA

  • Valor do TE
  • Valor do TUSD
  • Bandeira
  • Custo da bandeira
  • Taxa do fio B
    Este, eu fiz um teste e implementei acessando a API direto no meu HA. Com o receio da API falhar novamente… preciso avaliar como manter o valor caso a API falhe (provavelmente terei que criar um sensor de template)
    Vou compartilhar no final da msg como peguei.

Esse é o maior desaifo.
As informações abaixo, que eu saiba são federais, estaduais cada distribuidora trabalhar com um valor. É uma zona.
Teria que tentar achar um lugar com estas informações centralizadas, eu não achei…
O site da CPFL está uma m***a , era html , virou imagem, agora voltou para tabela html… descobri hoje que eu estou usando as % antigas pq meu script não encontra e ai esta mantendo valores antigos..

  • % PIS
  • % COFINS
  • % ICMS

PIS e COFINS , são federais, mas cada distribuidora calcula o seu, da CPFL fica nessa pagina : PIS-Cofins - CPFL Piratininga | CPFL
ICMS : a explicação fica nessa pagina , Tributos Municipais, Estaduais e Federais | CPFL , mas basicamente é : consumo até 90kwh = isento, consumo até 200 kwh = 12% , acima de 200kwh = 18%
Torcendo para que o IVA/CBS facilite isso…

Eu acredito que você teria que fazer funções especificas para cada distribuidora , de onde buscar a informação e cada vez que eles mexem na pagina, teria o retrabalho de fazer a extração novamente.

E com todos estes dados, trazer os valores para facilitar o calculo com os medidores de potencia e painel de energia.

  • TE+TUSD
  • TE+TUSD + aplicação dos impostos
  • Fio B com desconto de % referente ao Ano
  • Fio B com desconto de % referente ao Ano + aplicação dos impostos

REST - Taxa Fio B


rest:
  - resource: "https://dadosabertos.aneel.gov.br/api/3/action/datastore_search"
    scan_interval: 21600 # 6 horas...
    timeout: 30 
    params:
      # ID exclusivo do arquivo CSV de componentes tarifárias de 2025
      resource_id: "a4060165-3a0c-404f-926c-83901088b67c"
      # Filtros em formato JSON para extrair exatamente a linha desejada
      # Aqui usamos a acentuação correta que validamos no cURL
      filters: '{"SigNomeAgente": "CPFL-PIRATINING", "DscComponenteTarifario": "TUSD_FioB", "DscBaseTarifaria": "Tarifa de Aplicação", "DscSubGrupoTarifario": "B3", "DscModalidadeTarifaria": "Convencional"}'
    sensor:
      - name: "Tarifa Fio B CPFL Piratininga"
        unique_id: "tarifa_fio_b_cpfl_api"
        unit_of_measurement: "R$/kWh"
        device_class: monetary
        # Agora o HA vai ver que a API retornou 4 itens (length > 0) e habilitará o sensor
        value_template: >
          {% if value_json is defined and value_json.success and (value_json.result.records | length > 0) %}
            {# Pega o campo VlrComponenteTarifario do registro  (o primeiro dos 4 retornado) #}
            {# Usamos o 'first' para pegar o primeiro registro da lista com segurança #}
            {% set registro = value_json.result.records | first %}
            {% set valor_bruto = registro.VlrComponenteTarifario %}
            {# Troca a vírgula brasileira por ponto e converte para decimal #}
            {% set valor_decimal = valor_bruto | replace(',', '.') | float(0) %}
            {# Divide por 1000 para converter de MWh para kWh #}
            {{ (valor_decimal / 1000) | round(4) }}
          {% else %}
            {# Retorna 0 em caso de erro para não quebrar a validação monetária #}
            0
          {% endif %}
# Teste manual do acesso rest via curl
#  # $ curl -X POST "https://dadosabertos.aneel.gov.br/api/3/action/datastore_search"      -H "Content-Type: application/json"      -d '{
#  #            "resource_id": "a4060165-3a0c-404f-926c-83901088b67c",
#  #            "filters": {
#  #              "SigNomeAgente": "CPFL-PIRATINING",
#  #              "DscComponenteTarifario": "TUSD_FioB",
#  #              "DscBaseTarifaria": "Tarifa de Aplicação",
#  #              "DscSubGrupoTarifario": "B3",
#  #              "DscModalidadeTarifaria": "Convencional"
#  #            }
#  #          }' | jq

Opa, boa tarde @ceinmart!

Atualmente a extensão busca tarifa de qualquer operadora. Estou começando uma nova versão para separar em entidades os valores do TE e TUSD, calcular a taxa do fio B. A parte dos tributos realmente temos o problema de não ter a informação centralizada, porém a Receita Federal disponibilizou o IVA/CBS via API, tenho que ver como faz exatamente para acessar, pq não é aberto. Até isso entrar oficialmente, a opção seria realmente fazer por operadora e ir criando as interfaces para tentar extrair conforme a necessidade.

Eu entro de férias na quarta-feira, dai terei um pouco mais de tempo para seguir com essa nova versão.

Acabo de instalar sua integração. Parabéns! Também estou interessado nos valores de TE e TUSD.

@vodikus , boa noite!

A algumas semanas atras, criei uma extensão para coleta de API da FOXESS , aparelho de micro-inversor , para a fotovoltaia que instalei.
Juro, não escrevi uma unica linha de codigo, apenas um documento super detalhado e usei o codex/chatgpt para criar a extensão , ficou melhor que as extensões oficiais existentes no H.A. hoje.
Pra isso eu fiz uma assinatura “temporaria” do codex , aquelas assinaturas que não paga o primeiro mês.

Depois que te mandei a msg sobre os itens de coleta, pensei aqui , vou tentar aproveitar essa assinatura e ver o que consigo criar para resolver esse das tarifas.
Olha , ainda tem falhas, mas acho que avancei muito.
Coleta TE, TUSD, bandeira, Fio B , nas APIs da ANEEL (com tratativa de fallback caso a API falhe) , busca nos sites das concessionárias as informações sobre os impostos (PIS/COFINS/ICMS) , calcula valores para quem tem micro-geração/fotovoltaica (auto-consumo, valor de conta com a geração , saldo de credito, custo com Fio B).
Inclui também um calculo para tarifa branca, mas esse as regras são muito variaveis, não sei se vai rolar … a ideia é a pessoa saber se vale apena ou não migrar para tarifa branca.

Criei tudo isso no mesmo esquema , fazendo um documento bem estruturado com links , fontes e explicações.
As falhas que ocorreram no desenvolvimento , boa parte foram por falta de informação que eu não coloquei (por falha, ou esquecimento).

Então, pq estou te contando tudo isso?
Eu não sou desenvolvedor Python. Tenho conhecimento e experiencia com desenvolvimento, mas não com Python.
Não consigo revisar e validar esse codigo.
Minha intenção , seria tentar deixar esta extensão funcional e ver se você quer assumir a continuidade do desenvolvimento dela.
Não sei se codigo gerado por IA é algo facil de trabalhar…
Se este codigo não for facil de trabalhar e não tiver interesse em dar continuidade , fique a vontade para extrair as partes que lhe interessa para agregar na sua extensão.

bom dia @ceinmart !

Essas ferramentas são muito boas realmente. Eu uso bastante para diversas funções, validação de código e tal. As vezes fazem umas cabeçadas, mas se fizer sob supervisão, dá pra tirar um caldo hahaha

Vou analisar o código, ver como tá a estrutura e vemos como fazer um frankstein de tudo.

Em tempo, sobre a API da RF para pegar o IVA, só é liberado para CNPJ. Por mais que eu consiga o acesso e implemente isso na extensão futuramente, quem não tiver o acesso liberado lá vai acabar tendo essa funcionalidade prejudicada. Mas vou deixar isso guardado na gaveta para pensar mais pra frente!

Na segunda já estou de volta a minha cidade e consigo analisar e testar o código.

Obrigado!

Olha , muitos ajustes, mas acho que finalmente consegui dar uma boa laptada…
O fallback para o csv foi a maior dor de cabeça .
Não sei porque esses caras do site dadosabertos não disponibilizam o csv compactado , iria reduzir muito a transferencia.
Como a pagina estava com intermitencia , consegui testar bem o contorno pelo csv.

Os demais campos, me parecem corretos.
Os calculos também.
Porém , testei apenas para CPFL- PIRATININGA , ainda não testei para as outras duas concessionarias que ja tem suporte.

Essa é a coleta que iniciei a pouco , depois de alguns ajustes.



No atributos inclui varias informações para ajudar em diagnostico e entendimento dos valores :

Bom dia @ceinmart .

Dei uma olhada no código do seu repo e junto com o que já tinha aqui, comecei a montar a release 2.0.0 da extensão. Aproveitei para pegar um template modelo de extensões do HACS e coloquei na estrutura sugerida deles. Por enquanto está com a tag develop no repo, pois ainda estou testando em meu ambiente e provavelmente terá mais alterações.

Se quiser dar uma olhada, segue o link:

1 curtida

Show!
Dei uma olhada rapida nos seus prints, deu uma melhorada boa.

Eu vi que vc não fez o fork.
Eu apliquei mais algumas correções na parte de fallback para quando a API falha e na restauração dos dados quando a API falha , depois que te mandei a msg.. a ultima versão é a 0.1.9 .
Se não tiver pego esta , pega no diff as melhorias.

diaaa

ao tentar add o custom esta dando erro e no log aparece

Log details (ERROR)

This error originated from a custom integration.

Logger: custom_components.tarifas_energia_brasil.api
Source: custom_components/tarifas_energia_brasil/api.py:214
Integration: Tarifas de Energia Brasil ([documentation](https://github.com/vodikus/ha_tarifas_energia_brasil), [issues](https://github.com/vodikus/ha_tarifas_energia_brasil/issues))
First occurred: 23 de junho de 2026 às 13:01:44 (4 occurrences)
Last logged: 11:05:38

Erro ao acessar a API da ANEEL: 400, message='BAD REQUEST', url='https://dadosabertos.aneel.gov.br/api/3/action/datastore_search_sql?sql=SELECT+%22SigAgente%22+from+%22fcf2906c-7c32-4b9b-a637-054e7a5234f4%22+group+by+%22SigAgente%22'

Boa tarde!

Vou avaliar, mas pelo que olhei por alto, houve alguma mudança nas chamadas. Em breve já solto uma fix.

Boa tarde amigos! Espero que estejam todos bem!

Liberei um novo release (1.2.0) resolvendo o atual problema de consumo da API da ANEEL, que pelo que vi, mudou uma ação que usava para consultar as tarifas.

Fiz uma alteração um pouco mais robusta, mas necessária, visto que já não é a primeira vez que os “iluminados” lá alteram coisas e quebra o addon haha

A alteração consiste na adição de uma API que disponibilizei na Cloudflare, onde sempre libera a última atualização disponível no CSV. Eu tenho um serviço monitorando a atualização lá e que dispara essa atualização de base quando houver alteração.

O addon vai buscar a informação sempre que estiver próximo do fim da data de vigência da tarifa.

Caso tenham algum problema, me avisem. Tentarei resolver o mais rápido possível.

Um abraço a todos!

4 curtidas

vodikus

seria possivel um sensor já com o desconto do “FIO B” assim poderiamos calcular o valor economizado em casa conta, se comprarado ao valor cheio do KW!

Boa tarde @Oraculo .

Estou trabalhando na v2 do addon já com essa feature e outras. Como fiz a migração no final de semana para essa nova API, preciso refatorar também na v2. Além disso, estou planejando jogar a parte dos tributos para lá também.

Em breve libero um pre-release da v2.

Abraço!

2 curtidas