Saldo Cartão Refeição Santander - AppDaemon + Python + Selenium

Boas,

De forma a visualizar o saldo do cartão refeição do Santander no Home Assistant, configurei e desenvolvi o seguinte script aqui disponibilizado para quem necessitar de fazer o mesmo ou até para novas ideias.
Este projeto ainda está em fase de desenvolvimento/testes e melhoria, pelo que todas as opiniões, críticas ou sugestões serão sempre bem vindas.

---------- SANTANDER BALANCE ----------

Capturar

Add-On utilizados:

  • AppDaemon
  • Visual Studio Code ou File Editor

1º - Criar Sensor e Switch de atualização
De forma a termos presente o valor do saldo no dashboard, necessitamos de criar um sensor para o efeito. Utilizaremos o “Sensor Template”, bastando adicionar as linhas abaixo no nosso configuration.yaml

# Santander Balance Value
sensor:
  - platform: template
    sensors:
      santander_balance:
        value_template: "00,00"

O Switch é opcional, mas eu tinha em mente a possibilidade de querer despoletar manualmente ou até por uma automatização a atualização. Para o efeito recorremos ao “Switch Template” e adicionamos as linhas abaixo ao nosso configuration.yaml

switch:
# Santander Balance Update Switch
  - platform: template
    switches:
      updatebalance:
        turn_on:
          service: switch.turn_on
          target:
            entity_id: switch.updatebalance_on
        turn_off:
          service: switch.turn_off
          target:
            entity_id: switch.updatebalance_off

Como em qualquer outra alteração ao configuration.yaml, será necessário reiniciar o Home Assistant para que os sensores sejam carregados

2º - Criar cartão de visualização
No meu caso, criei um Dashboard específico para visualizar os dados presentes e adicionei um “Entities Card”

type: entities
entities:
  - entity: switch.updatebalance
    name: Atualizar
    secondary_info: last-changed
  - entity: sensor.santander_balance
    icon: mdi:currency-eur
    name: Saldo
    secondary_info: last-updated
state_color: true
show_header_toggle: false

3º - Configurar dependências Add-On AppDaemon
Após o download e instalação do Add-On AppDaemon, terão de ser configuradas algumas necessidades e dependências, nomeadamente o Chromium e o Selenium

system_packages:
  - chromium-chromedriver
  - chromium
python_packages:
  - selenium
init_commands: []

Aquando do arranque do Add-On, estas dependências irão ser instaladas e poderão ser importadas nos scripts.

4º - Configurar App no AppDaemon
Através do Visual Studio Code/File Editor, criar no diretório “/config/appdaemon/apps/” um ficheiro com o código da nossa App, nomeadamente “GetSantanderBalance.py”.

createfile

Abrir o ficheiro apps.yaml e adicionar a configuração da nossa app

SantanderBalance:
  module: GetSantanderBalance
  class: GetSantanderBalance

Gravar o ficheiro e abrir o GetSantanderBalance.py
Copiar o código abaixo para o ficheiro e alterar os valores identificados na função “GetBalance”

Na função "GetBalance" existem dois campos de texto a preencher:
"************** CARD NUMBER ***********" - Substituir pelo número de cartão sem espaços, exemplo "000000000"
"************** CARD CODE ***********" - Substituir pelo código do cartão, exemplo "123123"

Código:
Notas:

  • Sim, tem melhorias a fazer :sweat_smile:, foi desenvolvido por mim já a pensar em ir para a cama
  • O código espera que tenham o switch de atualização configurado, mas poderão adaptar o código para simplesmente atualizar o valor quando quiserem
  • Para a navegação no código HTML foi utilizado o XPATH bem como funções do Selenium
  • Devido aos iFrames presentes no site do Santander, é necessário saltar entre os mesmos para o contexto do seletor
  • Está previsto no código aceitar todos os cookies presentes no site

Melhorias a fazer quando possível:

  • Retirar timeout, isto torna o script mais lento, o mais correto seria a utilização de um wait for element com o devido seletor
  • Colocar o número de cartão numa variável mais acessível e de fácil configuração (usar ficheiro !secrets)
  • Colocar o código do cartão numa variável mais acessível e de fácil configuração(usar ficheiro !secrets)
  • Para testes, recorri ao run_minutely para executar a cada minuto, mas tal não é necessário podendo este tempo ser alargado a 30min ou mesmo 1h, irei ver no futuro com que recorrência necessito

Pequeno resumo:

  • Função initialize: Responsável por iniciar a aplicação e gerar as threads por minuto
  • Função CallListenProcess: É invocada pela inicialização da thread e é responsável por esperar que o switch de atualização mude para o estado ON, tendo um timeout de 59 segundos. Caso o switch não seja ativado, a thread é cancelada.
  • Função StartProcess: Arranca quando o swith é ligado e atribui os novos valores ao sensor e ao switch, no caso do switch irá desligá-lo
  • Função GetBalance: É responsável por toda a extração e movimentação no site Santander. Retorna o valor do saldo existente. No caso da existência de um erro, o saldo ficará a “0,00”
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import appdaemon.plugins.hass.hassapi as hass
import time
import datetime


class GetSantanderBalance(hass.Hass):

  def initialize(self):
    self.log("Starting Santander App")
    runtime  = datetime.time(0 ,0 ,0)
    self.run_minutely(self.CallListenProcess,runtime) 

  def CallListenProcess(self, kwargs):
    self.log("--------- SANTANDER BALANCE ---------")
    # listen for state ON for update balance
    self.listen_state(self.StartProcess,"switch.updatebalance", new = "on", timeout = 59)

  #Callback Function to Start the process 
  def StartProcess(self, entity, attribute, old, new, kwargs):
    self.log("-- SWITCH ON --")
    balance = self.GetBalance()
    self.log("Balance: " + balance)
    try:
      self.set_state('sensor.santander_balance', state = balance)
    except Exception as e:
      self.log("Set Sensor State Error: " + str(e))
    try:
      self.set_state("switch.updatebalance", state = old)
    except Exception as e:
      self.log("Set Swith State Error: " + str(e))

  def GetBalance(self):
    timeout = 4
    balance = "0,00"
    try:
      self.log("Start GetBalance")
      chrome_options = Options()
      chrome_options.add_argument('--headless')
      chrome_options.add_argument('--no-sandbox')
      chrome_options.add_argument('--disable-gpu')
      chrome_options.add_argument('--disable-dev-shm-usage')
      browser = webdriver.Chrome('chromedriver', options=chrome_options)
      try:
        self.log("Start Request")
        browser.get('https://www.particulares.santander.pt/pagina/indice/0,,840_1_2,00.html')
        time.sleep(timeout)
        try:
          browser.find_element_by_id('onetrust-accept-btn-handler').click()
        except Exception as e:
          self.log("No cookies")

        self.log("Login form")
        browser.switch_to.frame('ws')
        browser.find_element_by_xpath('//input[@autocomplete="userNameInputId"]').send_keys("************** CARD NUMBER ***********")
        browser.find_element_by_xpath('//input[@autocomplete="passwordInputId"]').send_keys("************** CARD CODE ***********")
        browser.find_element_by_id('submit_button').click()
        time.sleep(timeout)

        self.log("Success Login")
        browser.switch_to.frame('ws')
        time.sleep(timeout)

        self.log("Extracted Balance")
        balance = str(browser.find_element_by_xpath('//p[@class="balance-value text-green"]').text)
        browser.switch_to.default_content()

        self.log("Start Logout")
        browser.find_element_by_id('quick-logout').click()
        browser.close()
        self.log("Closed")
      except Exception as e:
        self.log("Request Error: " + str(e))
        browser.close()
    except Exception as e:
      self.log("GetBalance Error: " + str(e))
    return balance

Após guardar o ficheiro, o AppDaemon irá reiniciar o módulo e será possível visualizar nos logs do Add-On se tudo está conforme o esperado.

Próximo objetivo:

  • Executar as melhorias identificadas
  • Extrair os movimentos apresentados no banco
  • Apresentar os movimentos num cartão para posterior visualização no Dashboard

Notas finais:

  • Este é um projeto pessoal que disponibilizo a toda a gente na comunidade, poderão editar/alterar o código
  • Foi a minha primeira abordagem ao AppDaemon, pelo que poderão existir melhorias nesse aspeto também
  • O código está dependente dos seletores do site, pelo que, se o mesmo alterar, o script poderá deixar de funcionar

Estarei ao dispor para qualquer esclarecimento
Abraço

2 Curtiram

Funcional para o Brasil?

1 Curtiu

Boas
Não sei dizer…
O site em si não deve alterar muito, tens de trocar o link. Mas só testando…
Abraço

Baos noites.
Onde posso estar a falhar?
satander

Boas,

Pode verificar os logs do AppDaemon?
O resultado esperado será este aqui quando o switch fica ON

Abraço

Dá-me este erro.

ERROR 'log' directive deprecated, please convert to new 'logs' syntax

Qual o AppDaemon que está a correr? o 3 ou o 4?
Esse erro acontece quando já correu o 3 e é necessário migrar para o 4

https://github.com/hassio-addons/addon-appdaemon/issues/2

Abraço

Estou a correr o 4.
Agora da-me este erro
2021-11-12 18:55:21.322272 WARNING HASS: Disconnected from Home Assistant, retrying in 5 seconds

Edit: Problema resolvido eram problemas com o https.
Muito bom trabalho amigo Obrigado.

Parece ser mesmo um problema do AppDaemon e não do Script em si… Visto que o AppDaemon nem chega a ser inicializado.

Instalou o AppDaemon de raiz?
Tem algum certificado do estilo Let’s encript?
Talvez tentar desinstalar e instalar…

https://community.home-assistant.io/t/hadashboard-and-appdaemon-error-warning-disconnected-from-home-assistant-retrying-in-5-seconds/43898

Abraço

1 Curtiu

Problema Resolvido Obrigado.

satander

1 Curtiu

Era bom saber como foi resolvido para que outros utilizadores tenham essa informação se necessário…

Mas eu já mencionei foi devido a eu usar https…

1 Curtiu

@Boxexas,

Excelente partilha!

Fez-me ver que estava claramente a complicar na abordagem que estava a seguir para atingir o mesmo resultado. Eu uso o selenium para recolher informação de várias fontes, mas o que fiz foi levantar um container à parte (via Portainer) com python + selenium, usando scripts no AppDaemon para comunicar com ele através de mqtt, integrando depois os resultados no HA.

Muito mais complexo do que colocar os packages directamente no AppDaemon!!
Vou certamente migrar o que tenho para a tua abordagem, bem mais direta.

Obrigado!

1 Curtiu

Boa tarde.
Por aqui parece que correu bem no entanto tenho no log do HA o seguinte:

Logger: homeassistant.helpers.service
Source: helpers/service.py:129
First occurred: 12:30:36 PM (1 occurrences)
Last logged: 12:30:36 PM

Unable to find referenced entities switch.updatebalance_on

Eu acho que é quando o HA faz restart mas não tenho a certeza.
O que tenho a certeza é que quando o HA faz o restart o valor do saldo que tenho no meu cartão fica a 0 e não fica correto enquanto eu não aciono o botão de update.

Se puderem ajudar…
Obrigado

Boa tarde Jorge,

Sim, de facto tenho obtido o mesmo problema sempre que reinicio o servidor.
Inclusive tenho de desligar e ligar manualmente o switch para a atualização ficar a funcionar…

Irei tentar analisar e ver com mais calma, mas até agora não consegui resolver.

Abraço

Ok Tiago.
Desde já o meu obrigado pela resposta.
Vou então ficar a espera.
Cheguei a conclusão que quando aciono o botão de update dá o erro no log.

Boa noite Tiago.

Temos alguma novidade sobre este bug ?

O erro surge sempre que activo o update e confirmo que após restar o valor fica sempre a zero

Se precisar que faça alguns testes estou disponivel

Obrigado

Boas

Ainda não o consegui resolver, e não consigo perceber a origem… Desconfio que seja algo com o template do switch e o seu contexto, porque após a primeira utilização, ele funciona normalmente…

Abraço

Alguém sabe como ficaria para extrair o saldo deste site: https://www.verocard.com.br/para-voce. Não manjo nada.

Bom dia.
Depois de instalar o AppDaemon 0.9.1 deixou de funcionar o resto que funcionava.
Ele já não dava o valor do saldo sempre que se fazia reboot ao HA. Obrigava a carregar no botão.
Ao carregar no botãoi dava o erro que já tinha reportado anteriormente “Unable to find referenced entities switch.updatebalance_on” e agora nada funciona.

No log do appdeamon tem este erro sempre que carrego no botão e o valor continua a 0€, não sei se tem alguma coisa a ver.

2022-07-17 13:49:10.888326 INFO SantanderBalance: – SWITCH ON –
2022-07-17 13:49:10.892569 INFO SantanderBalance: Start GetBalance
2022-07-17 13:49:12.299647 INFO SantanderBalance: Start Request
2022-07-17 13:49:19.815522 INFO SantanderBalance: No cookies
2022-07-17 13:49:19.821944 INFO SantanderBalance: Login form
2022-07-17 13:49:20.133192 INFO SantanderBalance: Request Error: ‘WebDriver’ object has no attribute ‘find_element_by_xpath’
2022-07-17 13:49:20.405660 INFO SantanderBalance: Balance: 0,00
2022-07-17 13:49:20.496034 WARNING AppDaemon: callback StartProcess() in SantanderBalance has now completed


Copyright © 2017-2021. Todos os direitos reservados
CPHA.pt - info@cpha.pt


FAQ | Termos de Serviço/Regras | Política de Privacidade