[NOVA VERSAO] Próximos jogos, resultado ao vivo, tabela de classificação do seu time, notificação de gols

Salve galera, tudo certinho?

Refiz a integração do futebol agora com a API da ESPN, com ela e´ possível ver os próximos jogos, pegar dados da partida e a tabela de alguns campeonatos. Também adicionei para aviso de gols da partida ao vivo e melhores momentos, esses só funcionam em ‘grandes’ jogos, pelo menos em campeonato regional não deu certo.




  1. Baixe através do Hacs o card: HTML Jinja2 Template card
  • Use o código abaixo para fazer o card do ultimo jogo.
type: custom:html-template-card
ignore_line_breaks: true
content: >
  <div style="display: flex; flex-direction: column; align-items: center;
  background-color: none !important; padding: 20px; border-radius: 15px;
  box-shadow: none !important; font-family: Arial, sans-serif;">

    {% set data = state_attr('sensor.espn_futebol', 'last_match') %}
    {% set team = data.team if data and 'team' in data else {} %}
    {% set league = data.league %}
    {% set opponent = data.opponent if data and 'opponent' in data else {} %}
    {% set statistics = data.statistics if data and 'statistics' in data else [] %}
    {% set gols = data.Gols if data and 'Gols' in data else [] %}

    {%- macro normalize(text) -%}
      {{ text | lower | regex_replace("[áàãâä]", "a") | regex_replace("[éèêë]", "e") | regex_replace("[íìîï]", "i")| regex_replace("[óòõôö]", "o")| regex_replace("[úùûü]", "u") | regex_replace("[ç]", "c")| regex_replace("\s*de\s*", " ")| regex_replace("\s+", " ")| trim }}}}
    {%- endmacro %}

    <p style="font-size: 21px; color: var(--primary-text-color);; margin: 5px 0;">
      {{ league or 'Liga não disponível' }}
    </p>

    <div style="display: flex; justify-content: center; align-items: flex-start; margin: 20px 0; width: 100%;">

      <div style="text-align: center; flex: 1;">
        <img src="{{ team.Logo or 'https://via.placeholder.com/100' }}" alt="Time da Casa" style="width: 100px; height: 100px; border-radius: 10px;">
      <p style="margin: 10px 0 0 0; font-size: 16px; color: var(--primary-text-color);">
          {{ team.Name or ' ' }}
        </p>

        <div style="margin-top: 10px; text-align: center;">
          {% for gol in gols if normalize(gol.time) == normalize(team.Name) %}
            <p style="font-size: 12px; color: var(--primary-text-color); margin: 2px 0;">
              {{ gol.jogador }} - {{ gol.minuto }}
            </p>
          {% endfor %}
        </div>
      </div>

      <div style="text-align: center; flex: 0.5; font-size: 28px; font-weight: bold; color: var(--primary-text-color); align-self: center;">
        {{ team.Placar or 0 }} - {{ opponent.Placar or 0 }}
      </div>

      <div style="text-align: center; flex: 1;">
        <img src="{{ opponent.Logo or 'https://via.placeholder.com/100' }}" alt="Time Visitante" style="width: 100px; height: 100px; border-radius: 10px;">
        <p style="margin: 10px 0 0 0; font-size: 16px; color: var(--primary-text-color);">
          {{ opponent.Name or ' ' }}
        </p>

        <div style="margin-top: 10px; text-align: center;">
          {% for gol in gols if normalize(gol.time) == normalize(opponent.Name) %}
            <p style="font-size: 12px; color: var(--primary-text-color); margin: 2px 0;">
              {{ gol.jogador }} - {{ gol.minuto }}
            </p>
          {% endfor %}
        </div>
      </div>
    </div>

    {% set data = state_attr('sensor.espn_futebol', 'last_match') %}
    {% set statistics = data.statistics if data and 'statistics' in data else [] %}
    {% set teamColor = data.team.Color if data and 'team' in data and 'Color' in data.team else '#007bff' %}
    {% set opponentColor = data.opponent.Color if data and 'opponent' in data and 'Color' in data.opponent else '#ff073a' %}

    <table style="width: 100%; border-collapse: collapse; font-size: 12px; margin-top: -10px;">
      <thead>
        <tr>
          <th style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;"></th>
          <th style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;"></th>
          <th style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</th>
          <th style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;"></th>
        </tr>
      </thead>
      <tbody>
        {% for stat in statistics %}
          <tr style="background-color: {% if loop.index is divisibleby 2 %} var(--divider-color) {% else %} var(--input-background-color) {% endif %};">
            <td style="padding: 3px; border-bottom: 1px solid #ccc;">
              {% set iconMap = {
                "Chances Claras": "⚡",
                "Faltas": "🚩",
                "Cartões Amarelos": "🟨",
                "Cartões Vermelhos": "🟥",
                "Impedimentos": "🚫",
                "Escanteios": "📐",
                "Defesas": "🧤",
                "Posse de Bola": "⚽",
                "Total de Chutes": "🎯",
                "Chutes a Gol": "🥅",
                "Passes Certos": "✅",
                "Total de Passes": "🔄",
                "Cruzamentos": "📤",
                "Chutes Bloqueados": "🛡️",
                "Desarmes": "🦵",
                "Placar": "🪧",
                "Gols de Pênalti": "🤷‍♂️",
              } %}
              {{ iconMap[stat.stat_name] or '' }} {{ stat.stat_name }}
            </td>
            <td style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;">{{ stat.team or '-' }}</td>
            <td style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;">
              <div style="
                display: flex;
                align-items: center;
                justify-content: center;
                width: 100%;
                height: 8px;
                background: #ddd;
                border-radius: 5px;
                overflow: hidden;
                position: relative;
                border: 1px solid #ccc;
              ">
                {% set teamScore = stat.team | float(0) %}
                {% set opponentScore = stat.opponent | float(0) %}
                {% set totalScore = teamScore + opponentScore %}
                {% set teamPercentage = (teamScore / totalScore * 100) if totalScore > 0 else 50 %}
                <div style="height: 100%; width: {{ teamPercentage }}%; background-color: {{ teamColor }};"></div>
                <div style="height: 100%; width: {{ 100 - teamPercentage }}%; background-color: {{ opponentColor }};"></div>
              </div>
            </td>
            <td style="text-align: center; padding: 3px; border-bottom: 1px solid #ccc;">{{ stat.opponent or '-' }}</td>
          </tr>
        {% endfor %}
      </tbody>
    </table>
  </div>

  1. Baixe no Hacs o card: Team Tracker
  • Use o código abaixo para fazer o card do próximo jogo.
type: custom:teamtracker-card
entity: sensor.espn_futebol
show_league: true
show_rank: true
outline: false
show_timeouts: true
outline_color: blue
home_side: left
debug: false

  1. Baixe no Hacs o card: Flex Table
  • Use o código abaixo para fazer o card da tabela do campeonato.
type: custom:stack-in-card
mode: horizontal
cards:
  - type: custom:flex-table-card
    entities:
      include: sensor.espn_tabela
    columns:
      - name: "#"
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.stats[10].value + '</div>'"
      - name: Logo
        data: entries
        modify: >-
          '<div style="text-align: center;"><img src="' + x.team.logos[0].href +
          '" style="width: 10%;"></div>'
      - name: Equipe
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.team.name + '</div>'"
      - name: J
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.stats[0].value + '</div>'"
      - name: V
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.stats[7].value + '</div>'"
      - name: E
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.stats[6].value + '</div>'"
      - name: D
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.stats[1].value + '</div>'"
      - name: SG
        data: entries
        modify: |-
          {
            '<div style="text-align: center;">' +
            (x.stats[5].value - x.stats[4].value) +
            '</div>'
          }
      - name: Pontos
        data: entries
        modify: "'<div style=\"text-align: center;\">' + x.stats[3].value + '</div>'"
    strict: true

  1. Para mudar o campeonato voce pode utilizar um input_select.tabela_campeonatos
tabela_campeonatos:
  name: Selecionar Campeonato
  options:
    - "Campeonato Brasileiro (BRA.1)"
    - "Brazilian Serie B (BRA.2)"
    - "Brazilian Serie C (BRA.3)"
    - "Copa do Brasil (BRA.COPA_DO_BRAZIL)"
    - "UEFA Champions League (UEFA.CHAMPIONS)"
    - "UEFA Europa League (UEFA.EUROPA)"
    - "Copa do Mundo (FIFA.WORLD)"
    - "CONMEBOL Libertadores (CONMEBOL.LIBERTADORES)"
    - "CONMEBOL Sudamericana (CONMEBOL.SUDAMERICANA)"
    - "Campeonato Inglês (ENG.1)"
    - "Spanish LALIGA (ESP.1)"
    - "Campeonato Francês (FRA.1)"
    - "Bundesliga - Campeonato Alemão (GER.1)"
    - "Campeonato Italiano (ITA.1)"
    - "Copa das Nações da África (CAF.NATIONS)"
    - "Campeonato Chinês (CHN.1)"
    - "Campeonato Português (POR.1)"
    - "Mundial Feminino (FIFA.WWC)"
    - "Campeonato Paulista (BRA.CAMP.PAULISTA)"
    - "Campeonato Carioca (BRA.CAMP.CARIOCA)"
    - "Campeonato Gaúcho (BRA.CAMP.GAUCHO)"
    - "Campeonato Mineiro (BRA.CAMP.MINEIRO)"
    - "Copa do Nordeste (BRA.COPA_DO_NORDESTE)"
    - "Supercopa do Brasil (BRA.SUPERCOPA_DO_BRAZIL)"
    - "Eliminatórias Eurocopa (UEFA.EUROQ)"
    - "Copa São Paulo (BRA.SAOPAULO_YOUTH_CUP)"
    - "Copa América (CONMEBOL.AMERICA)"
    - "Amistoso (CLUB.FRIENDLY)"
    - "Brasileiro - S20 (BRA.BRASILEIRO_U20)"
    - "Copa do Brasil - S17 (BRA.COPA_DO_BRAZIL_U17)"
    - "Copa do Brasil - S20 (BRA.COPA_DO_BRAZIL_U20)"
    - "Panamericano - Futebol Feminino (PANAM.W)"
  initial: "Campeonato Brasileiro (BRA.1)"
  icon: mdi:trophy
  1. Para mudar o nome do time, crie um input_text.espn_team e adicione o nome do time que deseja pegar o status, caso não encontre ou de algum tipo de erro, entre no site da espn e veja se o nome dele não e´ escrito de forma diferente lá e tente novamente.

  2. Agora importe o código para o nodered

[{"id":"4b724119114337ed","type":"subflow","name":"Alexa fala","info":"","category":"","in":[{"x":120,"y":360,"wires":[{"id":"96709cccd273c329"},{"id":"da93b5086a8be64c"},{"id":"4f70e525d8f41ff5"},{"id":"5ace3ef7a8f10688"},{"id":"e1d234de24d7091e"},{"id":"259fe40bea0c8187"}]}],"out":[{"x":860,"y":360,"wires":[{"id":"9cfcabd8ce9c2dd0","port":0}]}],"env":[{"name":"escritorio","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"sala","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"quarto","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"suite","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"todas","type":"str","value":"","ui":{"type":"input","opts":{"types":["str"]}}},{"name":"","type":"str","value":"","ui":{"label":{"en-US":"Utilizar msg.alexa como variavel para passar informação"},"type":"none"}},{"name":"msg.alexa","type":"str","value":"","ui":{"type":"select","opts":{"opts":[{"l":{"en-US":"escritorio"},"v":"escritorio"},{"l":{"en-US":"sala"},"v":"sala"},{"l":{"en-US":"quarto"},"v":"quarto"},{"l":{"en-US":"suite"},"v":"suite"},{"l":{"en-US":"todas"},"v":"todas"},{"l":{"en-US":"null"},"v":""}]}}},{"name":"vol_fala","type":"num","value":"100","ui":{"type":"input","opts":{"types":["num"]}}},{"name":"vol_padrao","type":"num","value":"30","ui":{"type":"input","opts":{"types":["num"]}}}],"meta":{},"color":"#3FADB5","inputLabels":["cozinha / quarto / todas"],"icon":"node-red-contrib-alexa-remote2-applestrudel/alexa-remote-icon.png"},{"id":"3c6210e9c37d2c2a","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa escritorio","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"env","value":"escritorio"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G090XG0894371SGN"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G090XG0894371SGN"]}}]}},"x":540,"y":140,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"15b3c32b5643c45a","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa quarto","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"env","value":"quarto"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G0G2DB033146147J"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G0G2DB033146147J"]}}]}},"x":530,"y":180,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"d8289f16a9188f29","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa todas","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"env","value":"todas"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["51891e5ab3744b24b276a8f3d16d09ba"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["51891e5ab3744b24b276a8f3d16d09ba"]}}]}},"x":530,"y":260,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"7e6930f595ba955d","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa sala","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"msg","value":"alexa"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G0G2DB03314509S6"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G0G2DB03314509S6"]}}]}},"x":530,"y":480,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"bbb72289adee2f4a","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa quarto","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"msg","value":"alexa"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G0G2DB033146147J"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G0G2DB033146147J"]}}]}},"x":530,"y":520,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"6481a16bad9295e5","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa todas","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"msg","value":"alexa"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["51891e5ab3744b24b276a8f3d16d09ba"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["51891e5ab3744b24b276a8f3d16d09ba"]}}]}},"x":530,"y":600,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"4f70e525d8f41ff5","type":"switch","z":"4b724119114337ed","name":"escritorio","property":"escritorio","propertyType":"env","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":320,"y":140,"wires":[["3c6210e9c37d2c2a"]]},{"id":"da93b5086a8be64c","type":"switch","z":"4b724119114337ed","name":"quarto","property":"quarto","propertyType":"env","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":310,"y":180,"wires":[["15b3c32b5643c45a"]]},{"id":"96709cccd273c329","type":"switch","z":"4b724119114337ed","name":"todas","property":"todas","propertyType":"env","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":310,"y":260,"wires":[["d8289f16a9188f29"]]},{"id":"5ace3ef7a8f10688","type":"switch","z":"4b724119114337ed","name":"Qual alexa?","property":"msg.alexa","propertyType":"env","rules":[{"t":"eq","v":"escritorio","vt":"str"},{"t":"eq","v":"sala","vt":"str"},{"t":"eq","v":"quarto","vt":"str"},{"t":"eq","v":"suite","vt":"str"},{"t":"eq","v":"todas","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":310,"y":500,"wires":[["31aac769d2291208"],["7e6930f595ba955d"],["bbb72289adee2f4a"],["75b87aaaa1d66010"],["6481a16bad9295e5"]]},{"id":"ed682c3a9cb85bab","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa sala","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"env","value":"sala"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G0G2DB03314509S6"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G0G2DB03314509S6"]}}]}},"x":530,"y":220,"wires":[[]]},{"id":"e1d234de24d7091e","type":"switch","z":"4b724119114337ed","name":"sala","property":"sala","propertyType":"env","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":310,"y":220,"wires":[["ed682c3a9cb85bab"]]},{"id":"31aac769d2291208","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa escritorio","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"msg","value":"alexa"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G090XG0894371SGN"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G090XG0894371SGN"]}}]}},"x":540,"y":440,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"259fe40bea0c8187","type":"switch","z":"4b724119114337ed","name":"suite","property":"suite","propertyType":"env","rules":[{"t":"nempty"}],"checkall":"true","repair":false,"outputs":1,"x":310,"y":100,"wires":[["709a147ef734f02d"]]},{"id":"709a147ef734f02d","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa suite","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"env","value":"suite"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G090XG1220340B5S"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G090XG1220340B5S"]}}]}},"x":530,"y":100,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"75b87aaaa1d66010","type":"alexa-remote-routine","z":"4b724119114337ed","name":"Alexa suite","account":"d2d5e58c12932ab2","routineNode":{"type":"node","payload":{"type":"serial","children":[{"type":"speakAtVolume","payload":{"type":"regular","text":{"type":"msg","value":"alexa"},"volume":{"type":"env","value":"vol_fala"},"mode":"set","devices":["G090XG1220340B5S"]}},{"type":"volume","payload":{"value":{"type":"env","value":"vol_padrao"},"mode":{"type":"str","value":"set"},"devices":["G090XG1220340B5S"]}}]}},"x":530,"y":560,"wires":[["9cfcabd8ce9c2dd0"]]},{"id":"9cfcabd8ce9c2dd0","type":"junction","z":"4b724119114337ed","x":700,"y":360,"wires":[[]]},{"id":"d2d5e58c12932ab2","type":"alexa-remote-account","name":"","authMethod":"proxy","proxyOwnIp":"192.168.0.140","proxyPort":"3456","cookieFile":"/homeassistant/authAlexa","refreshInterval":"3","alexaServiceHost":"pitangui.amazon.com","pushDispatchHost":"","amazonPage":"amazon.com.br","acceptLanguage":"pt-BR","onKeywordInLanguage":"on","userAgent":"","usePushConnection":"on","autoInit":"on"},{"id":"37e033d25f1ace08","type":"tab","label":"-ESPN Futebol","disabled":false,"info":"","env":[]},{"id":"3b857c2ad83f94c0","type":"group","z":"37e033d25f1ace08","name":"Tabelas","style":{"label":true},"nodes":["function","aa18b2787c3ee65b","ef9423f47722fc96","bb3fc3454dbab5d1","http-request","9d3d7f68d5433799","f0c7293a0776767e"],"x":64,"y":39,"w":922,"h":142},{"id":"4f1473862f7c6795","type":"group","z":"37e033d25f1ace08","name":"Times","style":{"label":true},"nodes":["b987a171168b0a1b","fbbb4ecae540e1b8","fdc5d863503d6a55","1b9eec7aa52969d9","dde5f1167944c138","ebbff10205ad6be8","229a28fb3c2ca8df","8e0c8d70c610282e","74041b4270b1926b","1f83095254512b89","59e0b2cf121985f4","5980a92d311f728c","f320b8e357da1dd7","9ed874b6621534e7","9a76d5ae7d7e95f7","d3d82c9553f5208d","d6ea9d94bc6cad5a","91fbbd052bee174d","bf58e8ae47278ecb","e0151e09bd7c242d","2975c186bb2d8314","7154ae351a81c9bb","84e55e786724e195","ba6a5420f05f24c8","2e522e59d89df48d","0bee37d94f1810a8","778e632e07e842af","b72982ef40952e70","0526e3eb265894a8","98cc076ffc24034e","dc1e39d9c8b290f2"],"x":34,"y":259,"w":1652,"h":262},{"id":"be6cfbb1827a395c","type":"group","z":"37e033d25f1ace08","name":"Automações","style":{"label":true},"nodes":["1ff74e92a1d579ad","7c7a66e4d63a5a77","dcdd298101fecbeb","fdd13a61666334d8","1df59ada36d3f556","c51ae48feed0bfdb","c4856b5024f17dde","1ee62e5082c06f8d","95cdfa9eecce0e19","535ce6dd9a08d86a","8189baadf4ab750a","dbe3b8f77ca52e13","8ddfd8a6f41862b8","43b301c6ec80698b","89b5158aaa0e37a2","db91ab1997105d19","f3a6d843c5f9e4dd","f7b5919e868a446b","15c8cbd5f00bb3f9","f125c3cc80cc6236","27f947af362f82e5","3c292a9d23c38303","a926e78d88fe9810","ec8285a21126007c","5e2e8d02cb92eb59","4010e6284a33c629","9d6bc8f7e187f74d","94d83653c7a82417","03fee0dbf228e28e","2318f6a557b38709"],"x":54,"y":599,"w":1292,"h":362},{"id":"91fbbd052bee174d","type":"junction","z":"37e033d25f1ace08","g":"4f1473862f7c6795","x":780,"y":380,"wires":[["fdc5d863503d6a55","f320b8e357da1dd7"]]},{"id":"7154ae351a81c9bb","type":"junction","z":"37e033d25f1ace08","g":"4f1473862f7c6795","x":1260,"y":480,"wires":[["9ed874b6621534e7"]]},{"id":"84e55e786724e195","type":"junction","z":"37e033d25f1ace08","g":"4f1473862f7c6795","x":1220,"y":440,"wires":[["e0151e09bd7c242d"]]},{"id":"ba6a5420f05f24c8","type":"junction","z":"37e033d25f1ace08","g":"4f1473862f7c6795","x":1220,"y":400,"wires":[["9ed874b6621534e7"]]},{"id":"f7b5919e868a446b","type":"junction","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","x":620,"y":660,"wires":[["7c7a66e4d63a5a77","dcdd298101fecbeb"]]},{"id":"15c8cbd5f00bb3f9","type":"junction","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","x":620,"y":700,"wires":[["1df59ada36d3f556"]]},{"id":"f125c3cc80cc6236","type":"junction","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","x":1060,"y":880,"wires":[["27f947af362f82e5"]]},{"id":"27f947af362f82e5","type":"junction","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","x":1100,"y":840,"wires":[["dbe3b8f77ca52e13"]]},{"id":"3c292a9d23c38303","type":"junction","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","x":1060,"y":780,"wires":[["27f947af362f82e5"]]},{"id":"ec8285a21126007c","type":"junction","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","x":100,"y":920,"wires":[["1ee62e5082c06f8d"]]},{"id":"function","type":"function","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"Preparar Dados","func":"msg.payload = {\n    state: new Date().toISOString(),\n    attributes: {\n        entries: msg.payload.children[0].standings.entries\n    }\n};\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":700,"y":120,"wires":[["aa18b2787c3ee65b"]]},{"id":"aa18b2787c3ee65b","type":"ha-sensor","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"sensor tabela","entityConfig":"7275219dbc3a8c8d","version":0,"state":"on","stateType":"str","attributes":[],"inputOverride":"allow","outputProperties":[],"x":880,"y":120,"wires":[[]]},{"id":"ef9423f47722fc96","type":"server-state-changed","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"Tabela selecionada","server":"db1ab0af.caa65","version":6,"outputs":1,"exposeAsEntityConfig":"","entities":{"entity":["input_select.tabela_campeonatos"],"substring":[],"regex":[]},"outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"state","propertyType":"msg","value":"","valueType":"entityState"}],"x":190,"y":80,"wires":[["bb3fc3454dbab5d1"]]},{"id":"bb3fc3454dbab5d1","type":"function","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"function ","func":"\nif (msg.state && msg.state.includes(\"(\")) {\n    // Extrai o conteúdo entre os parênteses\n    let match = msg.state.match(/\\((.*?)\\)/);\n    if (match && match[1]) {\n        msg.state = match[1]; \n    } else {\n        msg.state = \"\"; \n    }\n} else {\n    msg.state = \"\"; \n}\n\nmsg.url = \"https://site.web.api.espn.com/apis/v2/sports/soccer/\"+msg.state+\"/standings?type=0&level=0\"\nmsg.headers = {\n    \"Content-Type\": \"application/json\"\n};\n\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":360,"y":120,"wires":[["http-request"]]},{"id":"http-request","type":"http request","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"Requisitar API","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":520,"y":120,"wires":[["function"]]},{"id":"9d3d7f68d5433799","type":"api-current-state","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"state time","server":"db1ab0af.caa65","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_select.tabela_campeonatos","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"state","propertyType":"msg","value":"","valueType":"entityState"},{"property":"timestamp","propertyType":"msg","value":"","valueType":"date"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":220,"y":140,"wires":[["bb3fc3454dbab5d1"]]},{"id":"f0c7293a0776767e","type":"inject","z":"37e033d25f1ace08","g":"3b857c2ad83f94c0","name":"","props":[],"repeat":"3600","crontab":"","once":true,"onceDelay":"40","topic":"","x":125,"y":140,"wires":[["9d3d7f68d5433799"]],"l":false},{"id":"b987a171168b0a1b","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"url time","func":"msg.url =\"https://site.web.api.espn.com/apis/search/v2?region=br&lang=pt&limit=1&page=1&type=team&dtciVideoSearch=true&query=\"+msg.state\nmsg.headers = {\n    \"Content-Type\": \"application/json\"\n};\n\n\nreturn msg;\n ","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":400,"wires":[["229a28fb3c2ca8df"]]},{"id":"fbbb4ecae540e1b8","type":"inject","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","props":[],"repeat":"60","crontab":"","once":true,"onceDelay":"40","topic":"","x":95,"y":400,"wires":[["98cc076ffc24034e"]],"l":false},{"id":"fdc5d863503d6a55","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"url jogos","func":"const content = msg.payload.results[0].contents[0].uid;\nconst result = content.split('t:')[1];\n\nmsg.id = result\n\nmsg.url = \"https://site.web.api.espn.com/apis/site/v2/sports/soccer/all/teams/\"+msg.id+\"/schedule?region=br&lang=pt&fixture=true\"\nmsg.headers = {\n    \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15\"\n};\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":880,"y":340,"wires":[["8e0c8d70c610282e"]]},{"id":"1b9eec7aa52969d9","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Dados sensor","func":"// Extrai a data do jogo e o timestamp atual\nconst gameDate = new Date(msg.payload.events?.[0]?.competitions?.[0]?.date).getTime() || 0; // Converte para timestamp UTC\nconst currentDate = new Date(msg.timestamp).getTime() || 0; // Já vem no formato timestamp UTC\n\n// Pega dados do flow\nconst liveMatchStats = flow.get('LiveMatchStatistics');\nconst eventos = flow.get('Eventos');\n\n// Calcula a diferença em milissegundos\nconst timeDiff = gameDate - currentDate;\n\n// Define a mensagem para \"Kickoff in\"\nlet kickoffMessage;\nif (timeDiff <= 0) {\n    kickoffMessage = \"O jogo já começou!\";\n} else if (timeDiff <= 60 * 1000) { // Menos de 1 minuto\n    kickoffMessage = \"em menos de 1 minuto\";\n} else if (timeDiff <= 60 * 60 * 1000) { // Menos de 1 hora\n    const minutesToKickoff = Math.ceil(timeDiff / (1000 * 60)); // Converte para minutos\n    kickoffMessage = `em ${minutesToKickoff} minuto${minutesToKickoff > 1 ? 's' : ''}`;\n} else if (timeDiff <= 24 * 60 * 60 * 1000) { // Menos de 24 horas\n    const hoursToKickoff = Math.ceil(timeDiff / (1000 * 60 * 60)); // Converte para horas\n    kickoffMessage = `em ${hoursToKickoff} hora${hoursToKickoff > 1 ? 's' : ''}`;\n} else if (timeDiff <= 7 * 24 * 60 * 60 * 1000) { // Entre 1 e 7 dias\n    const daysToKickoff = Math.ceil(timeDiff / (24 * 60 * 60 * 1000)); // Converte para dias\n    kickoffMessage = `em ${daysToKickoff} dia${daysToKickoff > 1 ? 's' : ''}`;\n} else if (timeDiff <= 14 * 24 * 60 * 60 * 1000) { // Entre 7 e 14 dias\n    kickoffMessage = \"em 1 semana\";\n} else if (timeDiff <= 21 * 24 * 60 * 60 * 1000) { // Entre 14 e 21 dias\n    kickoffMessage = \"em 2 semanas\";\n} else {\n    kickoffMessage = \" \";\n}\n\nconst gols = flow.get('gols') || []; // Recupera os gols armazenados no fluxo\n\nmsg.payload = {\n    state: msg.payload.events?.[0]?.competitions?.[0]?.status?.type?.state?.toUpperCase() || \" \",\n    attributes: {\n        'Sport': 'soccer',\n        'League': msg.payload.events?.[0]?.league?.name || \" \",\n        'League logo': 'https://a.espncdn.com/i/leaguelogos/soccer/500/' + (msg.payload.events?.[0]?.league?.alternateId || 'default') + '.png',\n        'Team abbr': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.team?.abbreviation || \" \",\n        'Opponent abbr': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.team?.abbreviation || \" \",\n        'Event name': msg.payload.events?.[0]?.shortName || \" \",\n        'Event url': msg.payload.events?.[0]?.links?.[0]?.href || \" \",\n        'Date': msg.payload.events?.[0]?.competitions?.[0]?.date || \" \",\n        'Kickoff in': kickoffMessage || \" \",\n        'Series summary': \" \",\n        'Venue': msg.payload.events?.[0]?.competitions?.[0]?.venue?.fullName || \" \",\n        'Location': (msg.payload.events?.[0]?.competitions?.[0]?.venue?.address?.city || \" \") + ', ' + (msg.payload.events?.[0]?.competitions?.[0]?.venue?.address?.country || \" \"),\n        'Tv network': \" \",\n        'Odds': \" \",\n        'Overunder': \" \",\n        'Team name': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.team?.displayName || \" \",\n        'Team ID': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.team?.id || \" \",\n        'Team record': msg.payload?.events?.[0]?.competitions?.[0]?.competitors?.[0]?.record?.[0]?.displayValue ?? \" \",\n        'Team rank': \" \",\n        'Team homeaway': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.homeAway || \" \",\n        'Team logo': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.team?.logos?.[0]?.href || 'https://a.espncdn.com/i/teamlogos/soccer/500/default-team-logo-500.png',\n        'Team url': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.team?.links?.[0]?.href || \" \",\n        'Team colors': liveMatchStats?.team?.Color || \"#fff\",\n        'Team score': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.score?.displayValue || \" \",\n        'Team win probability': \" \",\n        'Team winner': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.winner || false,\n        'Team timeouts': \" \",\n        'Team gols': gols\n            .filter(gol => gol.idTime === msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[0]?.team?.id)\n            .map(gol => ({\n                jogador: gol.jogador,\n                time: gol.time,\n                minuto: gol.minuto,\n                descricao: gol.descricao,\n                idTime: gol.idTime\n            })),\n        'Opponent name': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.team?.displayName || \" \",\n        'Opponent ID': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.team?.id || \" \",\n        'Opponent record': msg.payload?.events?.[0]?.competitions?.[0]?.competitors?.[1]?.record?.[0]?.displayValue ?? \" \",\n        'Opponent rank': \" \",\n        'Opponent homeaway': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.homeAway || \" \",\n        'Opponent logo': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.team?.logos?.[0]?.href || 'https://a.espncdn.com/i/teamlogos/soccer/500/default-team-logo-500.png',\n        'Opponent url': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.team?.links?.[0]?.href || \" \",\n        'Opponent colors': liveMatchStats?.opponent?.Color || \"#fff\",\n        'Opponent score': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.score?.displayValue || \" \",\n        'Opponent win probability': \" \",\n        'Opponent winner': msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.winner || false,\n        'Opponent gols': gols\n            .filter(gol => gol.idTime === msg.payload.events?.[0]?.competitions?.[0]?.competitors?.[1]?.team?.id)\n            .map(gol => ({\n                jogador: gol.jogador,\n                time: gol.time,\n                minuto: gol.minuto,\n                descricao: gol.descricao,\n                idTime: gol.idTime\n            })),\n        'Quarter': msg.payload.events?.[0]?.competitions?.[0]?.status?.period || \" \",\n        'Clock': msg.payload.events?.[0]?.competitions?.[0]?.status?.type?.detail || \" \",\n        'Possession': \" \",\n        'Last play': eventos?.stringTodosJuntos || \" \",\n        'Down distance text': \" \",\n        'Outs': \" \",\n        'Balls': \" \",\n        'Strikes': \" \",\n        'On first': \" \",\n        'On second': \" \",\n        'On third': \" \",\n        'Team shots on target': liveMatchStats?.team?.ShotsTarget || \" \",\n        'Team total shots': liveMatchStats?.team?.TotalShots || \" \",\n        'Opponent shots on target': liveMatchStats?.opponent?.ShotsTarget || \" \",\n        'Opponent total shots': liveMatchStats?.opponent?.TotalShots || \" \",\n        'Team sets won': \" \",\n        'Opponent sets won': \" \",\n        'Last update': msg.timestamp || \" \",\n        'Eventos' : flow.get(\"Eventos\"),\n\n        last_match: msg.payload.events?.[0]?.competitions?.[0]?.status?.type?.state?.toUpperCase() === \"IN\"\n            ? flow.get(\"LiveMatchStatistics\")\n            : flow.get(\"LastMatchStatistics\")\n\n    }\n};\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1140,"y":360,"wires":[["dde5f1167944c138"]]},{"id":"dde5f1167944c138","type":"ha-sensor","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"sensor time","entityConfig":"0ec7baaca4a6d27b","version":0,"state":"payload","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":1370,"y":360,"wires":[[]]},{"id":"ebbff10205ad6be8","type":"server-state-changed","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Time","server":"db1ab0af.caa65","version":6,"outputs":1,"exposeAsEntityConfig":"","entities":{"entity":["input_text.espn_team"],"substring":[],"regex":[]},"outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":true,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"state","propertyType":"msg","value":"","valueType":"entityState"},{"property":"timestamp","propertyType":"msg","value":"","valueType":"date"}],"x":170,"y":320,"wires":[["b987a171168b0a1b","b72982ef40952e70"]]},{"id":"229a28fb3c2ca8df","type":"http request","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Requisitar API","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":395,"y":400,"wires":[["dc1e39d9c8b290f2"]],"l":false},{"id":"8e0c8d70c610282e","type":"http request","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Requisitar API","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":965,"y":340,"wires":[["1f83095254512b89","74041b4270b1926b"]],"l":false},{"id":"74041b4270b1926b","type":"delay","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":1025,"y":360,"wires":[["1b9eec7aa52969d9"]],"l":false},{"id":"1f83095254512b89","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"URL Ao vivo","func":"if (msg.payload.events?.[0]?.competitions?.[0]?.status?.type?.state?.toUpperCase() === \"IN\") {\n\n    msg.url = \"https://site.web.api.espn.com/apis/site/v2/sports/soccer/all/summary?region=br&lang=pt&contentorigin=deportes&event=\" + msg.payload.events[0].id\n    msg.headers = {\n        \"Content-Type\": \"application/json\"\n    };\n    return msg;\n}\n\n\n\n ","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1130,"y":300,"wires":[["59e0b2cf121985f4"]]},{"id":"59e0b2cf121985f4","type":"http request","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1245,"y":300,"wires":[["5980a92d311f728c"]],"l":false},{"id":"5980a92d311f728c","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Dados ao vivo","func":"const liveMatchStats = flow.get('LiveMatchStatistics');\nfunction normalizeString(str) {\n    return str?.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\").toLowerCase();\n}\nconst live_match_statistics = {\n    league: msg.payload.header.league.name,\n    team: {\n        Name: msg.payload.header.competitions[0].competitors[0].team.name || \" \",\n        Logo: msg.payload.boxscore.teams[0].team.logo || 'https://a.espncdn.com/i/teamlogos/soccer/500/default-team-logo-500.png',\n        Color: \"#\" + msg.payload.header.competitions[0].competitors[0].team.color || \" \",\n        Abbreviation: msg.payload.header.competitions[0].competitors[0].team.abbreviation || \" \",\n        Placar: msg.payload.header.competitions[0].competitors[0].score || \" \",\n        HomeAway: msg.payload.header.competitions[0].competitors[0].homeAway || \" \",\n        Winner: msg.payload.header.competitions[0].competitors[0].winner || \" \",\n        ShotsTarget: msg.payload.boxscore.teams[0].statistics[8].displayValue || \" \",\n        TotalShots: msg.payload.boxscore.teams[0].statistics[7].displayValue || \" \",\n    },\n    opponent: {\n        Name: msg.payload.header.competitions[0].competitors[1].team.name || \" \",\n        Logo: msg.payload.boxscore.teams[1].team.logo || 'https://a.espncdn.com/i/teamlogos/soccer/500/default-team-logo-500.png',\n        Color: \"#\" + msg.payload.header.competitions[0].competitors[1].team.color || \" \",\n        Abbreviation: msg.payload.header.competitions[0].competitors[1].team.abbreviation || \" \",\n        Placar: msg.payload.header.competitions[0].competitors[1].score || \" \",\n        HomeAway: msg.payload.header.competitions[0].competitors[1].homeAway || \" \",\n        Winner: msg.payload.header.competitions[0].competitors[1].winner || \" \",\n        ShotsTarget: msg.payload.boxscore.teams[1].statistics[8].displayValue || \" \",\n        TotalShots: msg.payload.boxscore.teams[1].statistics[7].displayValue || \" \",\n    },\n    statistics: [\n        { stat_name: \"Chances Claras\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[26]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[26]?.displayValue || \" \" },\n        { stat_name: \"Faltas\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[0]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[0]?.displayValue || \" \" },\n        { stat_name: \"Cartões Amarelos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[1]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[1]?.displayValue || \" \" },\n        { stat_name: \"Cartões Vermelhos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[2]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[2]?.displayValue || \" \" },\n        { stat_name: \"Impedimentos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[3]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[3]?.displayValue || \" \" },\n        { stat_name: \"Escanteios\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[4]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[4]?.displayValue || \" \" },\n        { stat_name: \"Defesas\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[5]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[5]?.displayValue || \" \" },\n        { stat_name: \"Posse de Bola\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[6]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[6]?.displayValue || \" \" },\n        { stat_name: \"Total de Chutes\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[7]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[7]?.displayValue || \" \" },\n        { stat_name: \"Chutes a Gol\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[8]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[8]?.displayValue || \" \" },\n        { stat_name: \"Gols de Pênalti\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[11]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[11]?.displayValue || \" \" },\n        { stat_name: \"Passes Certos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[12]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[12]?.displayValue || \" \" },\n        { stat_name: \"Total de Passes\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[13]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[13]?.displayValue || \" \" },\n        { stat_name: \"Cruzamentos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[16]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[16]?.displayValue || \" \" },\n        { stat_name: \"Chutes Bloqueados\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[21]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[21]?.displayValue || \" \" },\n        { stat_name: \"Desarmes\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[23]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[23]?.displayValue || \" \" },\n        { stat_name: \"Placar\", team: msg.payload.header?.competitions?.[0]?.competitors?.[0]?.score || \" \", opponent: msg.payload.header?.competitions?.[0]?.competitors?.[1]?.score || \" \" }\n    ],\n    Gols: []\n};\n\n// Verifica se msg.payload.keyEvents existe e é um array\nif (msg.payload && Array.isArray(msg.payload.keyEvents)) {\n    msg.payload.keyEvents.forEach(event => {\n        if (event.type && event.type.text && /^Gol|Goal/.test(event.type.text)) {\n            const golInfo = {\n                jogador: event.participants && event.participants[0]?.athlete?.displayName || \" \",\n                time: event.team?.displayName || \" \",\n                minuto: event.clock?.displayValue || \" \",\n                descricao: event.text || \" \",\n                idTime: event.team?.id || \" \"\n            };\n\n            // Adiciona o gol ao array de gols\n            live_match_statistics.Gols.push(golInfo);\n        }\n    });\n}\n\nflow.set(\"LiveMatchStatistics\", live_match_statistics);\n\nconst keyEvents = Array.isArray(msg.payload.keyEvents) ? msg.payload.keyEvents : null;\n\nlet eventos = [];\nlet arrayClock = [];\nlet arrayType = [];\nlet arrayParticipants = [];\nlet arrayParticipants2 = [];\nlet arrayTeamAbbreviation = [];\n\nif (!keyEvents) {\n    const eventosData = {\n        arrayClock: [],\n        arrayType: [],\n        arrayParticipants: [],\n        arrayParticipants2: [],\n        arrayTeamAbbreviation: [],\n        stringTodosJuntos: \"\"\n    };\n\n    flow.set(\"Eventos\", eventosData);\n} else {\n    keyEvents.forEach(event => {\n        let eventoStr = \"\";\n\n        // Clock\n        if (event.clock && event.clock.displayValue) {\n            arrayClock.push(event.clock.displayValue);\n            eventoStr += event.clock.displayValue + \" \";\n        } else {\n            arrayClock.push(\"\");\n        }\n\n        // Type\n        if (event.type && event.type.text) {\n            arrayType.push(event.type.text);\n            eventoStr += event.type.text + \": \";\n        } else {\n            arrayType.push(\"\");\n        }\n\n        // Participants\n        if (event.participants && Array.isArray(event.participants)) {\n            let participantNames = [];\n            event.participants.forEach(participant => {\n                if (participant.athlete && participant.athlete.displayName) {\n                    participantNames.push(participant.athlete.displayName);\n                } else {\n                    participantNames.push(\"\"); // Adiciona string vazia se faltar o nome do participante\n                }\n            });\n            arrayParticipants.push(participantNames[0] || \"\"); // Primeiro participante no array original\n            arrayParticipants2.push(participantNames.slice(1).join(\", \") || \"\"); // Outros participantes\n            eventoStr += participantNames.join(\" → \") + \" \"; // Junta todos os participantes com \"→\" entre eles\n        } else {\n            arrayParticipants.push(\"\"); // Adiciona string vazia para o primeiro\n            arrayParticipants2.push(\"\"); // Adiciona string vazia para os demais\n        }\n\n        // Team Abbreviation\n        if (event.team && event.team.displayName) {\n            const normalizedEventTeamName = normalizeString(event.team.displayName);\n            const normalizedTeamName = normalizeString(live_match_statistics.team.Name);\n            const normalizedOpponentName = normalizeString(live_match_statistics.opponent.Name);\n\n            let teamAbbreviation = \"\";\n            if (normalizedEventTeamName === normalizedTeamName) {\n                teamAbbreviation = live_match_statistics.team.Abbreviation || \"\";\n            } else if (normalizedEventTeamName === normalizedOpponentName) {\n                teamAbbreviation = live_match_statistics.opponent.Abbreviation || \"\";\n            } else if (event.team && event.team.abbreviation) {\n                teamAbbreviation = event.team.abbreviation;\n            } else {\n                teamAbbreviation = event.team.displayName || \"\";\n            }\n            arrayTeamAbbreviation.push(teamAbbreviation.trim());\n            eventoStr += `(${teamAbbreviation.trim()})`;\n        } else {\n            arrayTeamAbbreviation.push(\"\");\n        }\n\n        // Add event to array if not empty\n        if (eventoStr.trim() !== \"\") {\n            eventos.push(eventoStr.trim());\n        }\n    });\n}\n\n// Estrutura para salvar\nconst eventosData = {\n    arrayClock: arrayClock,\n    arrayType: arrayType,\n    arrayParticipants: arrayParticipants,\n    arrayParticipants2: arrayParticipants2,\n    arrayTeamAbbreviation: arrayTeamAbbreviation,\n    stringTodosJuntos: eventos.join(\" \\n \")\n};\n\n// Salvando no flow\nflow.set(\"Eventos\", eventosData);\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1380,"y":300,"wires":[[]]},{"id":"f320b8e357da1dd7","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"URL ultimo jogo","func":"const content = msg.payload.results[0].contents[0].uid;\nconst result = content.split('t:')[1];\n\nmsg.id = result\n\nmsg.url = \"https://site.web.api.espn.com/apis/site/v2/sports/soccer/all/teams/\" + msg.id +\"/schedule?region=br&lang=pt&season=2025\"\nmsg.headers = {\n    \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15\"\n};\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":900,"y":420,"wires":[["d3d82c9553f5208d"]]},{"id":"9ed874b6621534e7","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"ID evento","func":"msg.url = \"https://site.web.api.espn.com/apis/site/v2/sports/soccer/all/summary?region=br&lang=pt&contentorigin=deportes&event=\" + msg.payload.events[0].id\nmsg.headers = {\n    \"Content-Type\": \"application/json\"\n};\n\n\nreturn msg;\n ","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1360,"y":440,"wires":[["9a76d5ae7d7e95f7"]]},{"id":"9a76d5ae7d7e95f7","type":"http request","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1455,"y":440,"wires":[["d6ea9d94bc6cad5a"]],"l":false},{"id":"d3d82c9553f5208d","type":"http request","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1025,"y":420,"wires":[["bf58e8ae47278ecb"]],"l":false},{"id":"d6ea9d94bc6cad5a","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Dados ultimo jogo","func":"const last_match_statistics = {\n    league: msg.payload.header.league.name,\n    team: {\n        Name: msg.payload.header.competitions[0].competitors[0].team.displayName || \" \",\n        Logo: msg.payload.boxscore.teams[0].team.logo || 'https://a.espncdn.com/i/teamlogos/soccer/500/default-team-logo-500.png',\n        Color: \"#\" + msg.payload.header.competitions[0].competitors[0].team.color || \" \",\n        Abbreviation: msg.payload.header.competitions[0].competitors[0].team.abbreviation || \" \",\n        Placar: msg.payload.header.competitions[0].competitors[0].score || \" \",\n        HomeAway: msg.payload.header.competitions[0].competitors[0].homeAway || \" \",\n        Winner: msg.payload.header.competitions[0].competitors[0].winner || \" \",\n\n    },\n    opponent: {\n        Name: msg.payload.header.competitions[0].competitors[1].team.displayName || \" \",\n        Logo: msg.payload.boxscore.teams[1].team.logo || 'https://a.espncdn.com/i/teamlogos/soccer/500/default-team-logo-500.png',\n        Color: \"#\" + msg.payload.header.competitions[0].competitors[1].team.color || \" \",\n        Abbreviation: msg.payload.header.competitions[0].competitors[1].team.abbreviation || \" \",\n        Placar: msg.payload.header.competitions[0].competitors[1].score || \" \",\n        HomeAway: msg.payload.header.competitions[0].competitors[1].homeAway || \" \",\n        Winner: msg.payload.header.competitions[0].competitors[1].winner || \" \",\n    },\n    statistics: [\n        { stat_name: \"Chances Claras\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[26]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[26]?.displayValue || \" \" },\n        { stat_name: \"Faltas\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[0]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[0]?.displayValue || \" \" },\n        { stat_name: \"Cartões Amarelos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[1]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[1]?.displayValue || \" \" },\n        { stat_name: \"Cartões Vermelhos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[2]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[2]?.displayValue || \" \" },\n        { stat_name: \"Impedimentos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[3]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[3]?.displayValue || \" \" },\n        { stat_name: \"Escanteios\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[4]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[4]?.displayValue || \" \" },\n        { stat_name: \"Defesas\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[5]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[5]?.displayValue || \" \" },\n        { stat_name: \"Posse de Bola\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[6]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[6]?.displayValue || \" \" },\n        { stat_name: \"Total de Chutes\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[7]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[7]?.displayValue || \" \" },\n        { stat_name: \"Chutes a Gol\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[8]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[8]?.displayValue || \" \" },\n        { stat_name: \"Gols de Pênalti\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[11]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[11]?.displayValue || \" \" },\n        { stat_name: \"Passes Certos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[12]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[12]?.displayValue || \" \" },\n        { stat_name: \"Total de Passes\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[13]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[13]?.displayValue || \" \" },\n        { stat_name: \"Cruzamentos\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[16]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[16]?.displayValue || \" \" },\n        { stat_name: \"Chutes Bloqueados\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[21]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[21]?.displayValue || \" \" },\n        { stat_name: \"Desarmes\", team: msg.payload.boxscore?.teams?.[0]?.statistics?.[23]?.displayValue || \" \", opponent: msg.payload.boxscore?.teams?.[1]?.statistics?.[23]?.displayValue || \" \" },\n        { stat_name: \"Placar\", team: msg.payload.header?.competitions?.[0]?.competitors?.[0]?.score || \" \", opponent: msg.payload.header?.competitions?.[0]?.competitors?.[1]?.score || \" \" }\n    ], \n    Gols: []\n};\n\n// Verifica se msg.payload.keyEvents existe e é um array\nif (msg.payload && Array.isArray(msg.payload.keyEvents)) {\n    msg.payload.keyEvents.forEach(event => {\n        if (event.type && event.type.text && /^Gol|Goal/.test(event.type.text)) {\n            const golInfo = {\n                jogador: event.participants && event.participants[0]?.athlete?.displayName || \" \",\n                time: event.team?.displayName || \" \",\n                minuto: event.clock?.displayValue || \" \",\n                descricao: event.text || \" \",\n                idTime: event.team?.id || \" \"\n            };\n\n            // Adiciona o gol ao array de gols\n            last_match_statistics.Gols.push(golInfo);\n        }\n    });\n}\n\n// Armazena tudo no flow\nflow.set(\"LastMatchStatistics\", last_match_statistics);\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1570,"y":440,"wires":[[]]},{"id":"1ff74e92a1d579ad","type":"switch","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Tempo antes da partida para ser avisado","property":"data.new_state.attributes.kickoff_in","propertyType":"msg","rules":[{"t":"eq","v":"em 5 minutos","vt":"str"},{"t":"eq","v":"O jogo já começou!","vt":"str"},{"t":"eq","v":"O pacote foi assinado para","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":440,"y":680,"wires":[["f7b5919e868a446b"],["15c8cbd5f00bb3f9"],[]]},{"id":"7c7a66e4d63a5a77","type":"api-current-state","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Em casa?","server":"db1ab0af.caa65","version":3,"outputs":2,"halt_if":"home","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.kelvin_em_casa","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload_state","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":760,"y":640,"wires":[["94d83653c7a82417"],[]]},{"id":"dcdd298101fecbeb","type":"template","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Deseja receber os eventos da partida?","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"O jogo {{data.new_state.attributes.team_name}} contra {{data.new_state.attributes.opponent_name}} \" vai começar. Deseja receber as informações da partida?","output":"str","x":850,"y":720,"wires":[["5e2e8d02cb92eb59"]]},{"id":"fdd13a61666334d8","type":"link out","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Envia pergunta telegram","mode":"link","links":["3dcd30a4d7ef48cc"],"x":1190,"y":720,"wires":[],"l":true},{"id":"1df59ada36d3f556","type":"switch","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Contém a palavra \"O jogo\" na mensagem telegram","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"O jogo","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":645,"y":780,"wires":[["c51ae48feed0bfdb"]],"l":false},{"id":"c51ae48feed0bfdb","type":"change","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"resposta = YES","rules":[{"t":"set","p":"payload","pt":"msg","to":"YES","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":780,"wires":[["89b5158aaa0e37a2"]]},{"id":"c4856b5024f17dde","type":"link in","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Resposta YES","links":["9bd24a5d37976115"],"x":520,"y":780,"wires":[["1df59ada36d3f556"]],"icon":"node-red-contrib-telegrambot-home/telegram.png","l":true},{"id":"1ee62e5082c06f8d","type":"trigger","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Valida cada 10s","op1":"","op2":"","op1type":"pay","op2type":"str","duration":"-10","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":220,"y":860,"wires":[["95cdfa9eecce0e19"]]},{"id":"95cdfa9eecce0e19","type":"api-current-state","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Atributos - Last play","server":"db1ab0af.caa65","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.espn_futebol","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":420,"y":860,"wires":[["43b301c6ec80698b"]]},{"id":"535ce6dd9a08d86a","type":"function","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Último evento","func":"const eventosData = msg.data.attributes.eventos;\n\n// Mapeamento de tipos de eventos para emoticons\nconst tipoEventoEmoticons = {\n    \"Gol\": \"⚽ \",\n    \"Cartão amarelo\": \"🟨 \",\n    \"Cartão vermelho\": \"🟥 \",\n    \"Gol de pênalti\": \"⚽ \",\n    \"substituição\": \"🔄 \",\n    \"Gol de falta\": \"⚽ \",\n    \"Intervalo\": \"⏸️ \"\n};\n\n// Verifica se os dados existem antes de acessar as propriedades\nif (eventosData) {\n    // Últimos elementos de cada array\n    const ultimoClock = eventosData.arrayClock[eventosData.arrayClock.length - 1] || \"\";\n    const ultimoType = eventosData.arrayType[eventosData.arrayType.length - 1] || \"\";\n    const ultimoParticipant = eventosData.arrayParticipants[eventosData.arrayParticipants.length - 1] || \"\";\n    const ultimoParticipant2 = eventosData.arrayParticipants2 ? eventosData.arrayParticipants2[eventosData.arrayParticipants2.length - 1] : \"\"; // Verifica se há um segundo participante\n    const ultimoTeamAbbreviation = eventosData.arrayTeamAbbreviation[eventosData.arrayTeamAbbreviation.length - 1] || \"\";\n\n    // Converte o tipo de evento, se necessário\n    let tipoEventoConvertido = ultimoType;\n    if (ultimoType === \"Goal - Free-kick\") {\n        tipoEventoConvertido = \"Gol de falta\";\n    } else if (ultimoType === \"Meio tempo\") {\n        tipoEventoConvertido = \"Intervalo\";\n    }\n\n    // Adiciona os últimos valores ao objeto msg\n    msg.ultimoClock = ultimoClock;\n    msg.ultimoType = tipoEventoConvertido;\n    msg.ultimoParticipant = ultimoParticipant;\n    msg.ultimoParticipant2 = ultimoParticipant2;\n    msg.ultimoTeamAbbreviation = ultimoTeamAbbreviation;\n\n    // Obtém o emoticon correspondente ao tipo de evento\n    const emoticon = tipoEventoEmoticons[tipoEventoConvertido] || \"📋 \"; // Padrão: ponto de interrogação\n\n    // Combina os últimos elementos para formar o último evento\n    if (tipoEventoConvertido.toLowerCase() === \"substituição\") {\n        // Se for substituição, inclui o segundo participante\n        msg.ultimoEvento = `🕔 ${msg.ultimoClock}\\n${emoticon} ${tipoEventoConvertido}\\n\\n${msg.ultimoParticipant} → ${msg.ultimoParticipant2} (${msg.ultimoTeamAbbreviation})`.trim();\n    } else {\n        // Para outros eventos, mantém o formato padrão\n        msg.ultimoEvento = `🕔 ${msg.ultimoClock}\\n${emoticon} ${tipoEventoConvertido}\\n\\n${msg.ultimoParticipant} (${msg.ultimoTeamAbbreviation})`.trim();\n    }\n\n    // Compara o último evento com o evento armazenado no fluxo\n    const ultimoEventoAnterior = flow.get(\"UltimoEvento\") || \"\";\n    if (ultimoEventoAnterior !== msg.ultimoEvento) {\n        // Atualiza o evento no fluxo\n        flow.set(\"UltimoEvento\", msg.ultimoEvento);\n\n        // Retorna a mensagem se o último evento mudou\n        return [msg, null];\n    }\n}\n\n\nconst eventosGols = msg.data.attributes.eventos;\nconst gols = msg.data.attributes.last_match.Gols;\n\n// Verifica se há dados de eventos e gols antes de acessar as propriedades\nif (eventosGols && gols) {\n    // Último gol do array de gols\n    const ultimoGol = gols[gols.length - 1] || null;\n\n    if (ultimoGol) {\n        // Extrai informações relevantes do último gol\n        const minuto = ultimoGol.minuto || \"\";\n        const jogador = ultimoGol.jogador || \"\";\n        const time = ultimoGol.time || \"\";\n        const descricao = ultimoGol.descricao || \"\";\n\n        // Combina as informações do último gol\n        msg.ultimoGol = `🕔 ${minuto}\\n⚽ ${jogador} (${time})\\n\\n${descricao}`.trim();\n\n        // Compara o último gol com o gol armazenado no fluxo\n        const ultimoGolAnterior = flow.get(\"UltimoGol\") || \"\";\n        if (ultimoGolAnterior !== msg.ultimoGol) {\n            // Atualiza o último gol no fluxo\n            flow.set(\"UltimoGol\", msg.ultimoGol);\n\n            // Retorna a mensagem se o último gol mudou\n            return [null, msg];\n        }\n    }\n}\n","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":860,"wires":[["8189baadf4ab750a"],["a926e78d88fe9810"]]},{"id":"8189baadf4ab750a","type":"template","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Evento","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"👟 EVENTO FUTEBOL 👟\n\n\n{{{flow.LiveMatchStatistics.team.Name}}} {{{flow.LiveMatchStatistics.team.Placar}}} - {{{flow.LiveMatchStatistics.opponent.Placar}}} {{{flow.LiveMatchStatistics.opponent.Name}}}\n\n{{{ultimoEvento}}}\n\n","output":"str","x":920,"y":840,"wires":[["27f947af362f82e5"]]},{"id":"dbe3b8f77ca52e13","type":"link out","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Envia msg telegram","mode":"link","links":["0d20d93e76ce11d7"],"x":1220,"y":840,"wires":[],"l":true},{"id":"8ddfd8a6f41862b8","type":"change","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"reset","rules":[{"t":"set","p":"reset","pt":"msg","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":730,"y":920,"wires":[["ec8285a21126007c","2318f6a557b38709"]]},{"id":"43b301c6ec80698b","type":"switch","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Ao vivo?","property":"data.attributes.kickoff_in","propertyType":"msg","rules":[{"t":"eq","v":"O jogo já começou!","vt":"str"},{"t":"neq","v":"O jogo já começou!","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":600,"y":860,"wires":[["535ce6dd9a08d86a"],["8ddfd8a6f41862b8"]]},{"id":"89b5158aaa0e37a2","type":"template","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Aviso ","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"👟 EVENTO FUTEBOL 👟\n\n⚠️ ⚠️ ⚠️  ⚠️ ⚠️ ⚠️\n\nAssim que tiver eventos nessa partida você será notificado!! \n\n","output":"str","x":910,"y":780,"wires":[["1ee62e5082c06f8d","3c292a9d23c38303"]]},{"id":"db91ab1997105d19","type":"server-state-changed","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Entidade - Atributos","server":"db1ab0af.caa65","version":6,"outputs":1,"exposeAsEntityConfig":"","entities":{"entity":["sensor.espn_futebol"],"substring":[],"regex":[]},"outputInitially":false,"stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is","outputOnlyOnStateChange":false,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":170,"y":680,"wires":[["1ff74e92a1d579ad"]]},{"id":"f3a6d843c5f9e4dd","type":"template","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Fim de jogo","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"👟 EVENTO FUTEBOL - FIM DE JOGO 👟\n\n\n {{{flow.LiveMatchStatistics.team.Name}}} {{{flow.LiveMatchStatistics.team.Placar}}} - {{{flow.LiveMatchStatistics.opponent.Placar}}} {{{flow.LiveMatchStatistics.opponent.Name}}}\n\nResumo da partinda:\n\n👇👇👇👇👇\n\n{{{flow.Eventos.stringTodosJuntos}}}\n","output":"str","x":930,"y":920,"wires":[["f125c3cc80cc6236","ec8285a21126007c"]]},{"id":"bf58e8ae47278ecb","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"24 ou 25?","func":"// CAMPEONATOS 2025\nif (msg.payload.events.length != 0) {\n    return [msg,null]\n} \n// CAMPEONATOS 2024\nelse {\n    msg.url = \"https://site.web.api.espn.com/apis/site/v2/sports/soccer/all/teams/\" + msg.id + \"/schedule?region=br&lang=pt&season=2024\"\n    msg.headers = {\n        \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15\"\n    };\n    return [null,msg]\n}\n","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1120,"y":420,"wires":[["ba6a5420f05f24c8"],["84e55e786724e195"]]},{"id":"e0151e09bd7c242d","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"URL ultimo jogo","func":"msg.url = \"https://site.web.api.espn.com/apis/site/v2/sports/soccer/all/teams/\" + msg.id +\"/schedule?region=br&lang=pt&season=2024\"\nmsg.headers = {\n    \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15\"\n};\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":900,"y":480,"wires":[["2975c186bb2d8314"]]},{"id":"2975c186bb2d8314","type":"http request","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"c159a5512ccbc528","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":1025,"y":480,"wires":[["7154ae351a81c9bb"]],"l":false},{"id":"a926e78d88fe9810","type":"template","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Gol","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"👟 EVENTO FUTEBOL - GOOOOOOL 👟\n\n {{{flow.LiveMatchStatistics.team.Name}}} {{{flow.LiveMatchStatistics.team.Placar}}} - {{{flow.LiveMatchStatistics.opponent.Placar}}} {{{flow.LiveMatchStatistics.opponent.Name}}}\n\n👇👇👇👇👇\n\n{{{ultimoGol}}}\n","output":"str","x":910,"y":880,"wires":[["f125c3cc80cc6236"]]},{"id":"5e2e8d02cb92eb59","type":"delay","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"2","rateUnits":"hour","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":1045,"y":720,"wires":[["fdd13a61666334d8"]],"l":false},{"id":"4010e6284a33c629","type":"subflow:4b724119114337ed","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"","env":[{"name":"msg.alexa","value":"sala","type":"str"},{"name":"vol_fala","value":"70","type":"num"},{"name":"vol_padrao","value":"50","type":"num"}],"x":1060,"y":640,"wires":[[]]},{"id":"9d6bc8f7e187f74d","type":"function","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"MSG","func":"msg.alexa = \"O jogo \" + msg.data.new_state.attributes.team_name + \" contra \" + msg.data.new_state.attributes.opponent_name + \"vai começar.\"\n\nreturn msg;","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":930,"y":640,"wires":[["4010e6284a33c629"]]},{"id":"94d83653c7a82417","type":"delay","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"2","rateUnits":"hour","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"allowrate":false,"outputs":1,"x":855,"y":640,"wires":[["9d6bc8f7e187f74d"]],"l":false},{"id":"03fee0dbf228e28e","type":"link in","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"link in 1","links":["778e632e07e842af"],"x":95,"y":860,"wires":[["1ee62e5082c06f8d"]]},{"id":"2e522e59d89df48d","type":"api-current-state","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Sensor","server":"db1ab0af.caa65","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.espn_futebol","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":500,"y":320,"wires":[["0bee37d94f1810a8"]]},{"id":"0bee37d94f1810a8","type":"switch","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Ao vivo?","property":"data.attributes.kickoff_in","propertyType":"msg","rules":[{"t":"eq","v":"O jogo já começou!","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":640,"y":320,"wires":[["778e632e07e842af"]]},{"id":"778e632e07e842af","type":"link out","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"link out 1","mode":"link","links":["03fee0dbf228e28e"],"x":735,"y":320,"wires":[]},{"id":"b72982ef40952e70","type":"function","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"zerar flow","func":"if (msg.state != \"Time não encontrado, tente novamente\") {\n\n    flow.set(\"Eventos\", \" \")\n    flow.set(\"UltimoEvento\", \" \")\n    flow.set(\"UltimoGol\", \" \")\n\n    return msg\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":300,"y":320,"wires":[["0526e3eb265894a8"]]},{"id":"0526e3eb265894a8","type":"delay","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":395,"y":320,"wires":[["2e522e59d89df48d"]],"l":false},{"id":"2318f6a557b38709","type":"switch","z":"37e033d25f1ace08","g":"be6cfbb1827a395c","name":"Contém a palavra \"O jogo\" na mensagem telegram","property":"Eventos","propertyType":"flow","rules":[{"t":"neq","v":" ","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":825,"y":920,"wires":[["f3a6d843c5f9e4dd"]],"l":false},{"id":"98cc076ffc24034e","type":"api-current-state","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"Time","server":"db1ab0af.caa65","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"input_text.espn_team","state_type":"str","blockInputOverrides":true,"outputProperties":[{"property":"state","propertyType":"msg","value":"","valueType":"entityState"},{"property":"timestamp","propertyType":"msg","value":"iso","valueType":"date"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":170,"y":400,"wires":[["b987a171168b0a1b"]]},{"id":"dc1e39d9c8b290f2","type":"switch","z":"37e033d25f1ace08","g":"4f1473862f7c6795","name":"","property":"payload.results[0].type","propertyType":"msg","rules":[{"t":"eq","v":"team","vt":"str"},{"t":"neq","v":"team","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":455,"y":400,"wires":[["91fbbd052bee174d"],[]],"l":false},{"id":"7275219dbc3a8c8d","type":"ha-entity-config","server":"db1ab0af.caa65","deviceConfig":"","name":"espn_tabela","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"espn_tabela"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"db1ab0af.caa65","type":"server","name":"Home Assistant","version":5,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30","areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m","enableGlobalContextStore":true},{"id":"c159a5512ccbc528","type":"tls-config","name":"","cert":"","key":"","ca":"","certname":"","keyname":"","caname":"","servername":"","verifyservercert":false,"alpnprotocol":""},{"id":"0ec7baaca4a6d27b","type":"ha-entity-config","server":"db1ab0af.caa65","deviceConfig":"","name":"espn_futebol","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"espn_futebol"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false}]

OBS IMPORTANTE: o nome dos sensores tem que ser iguais aos que eu fiz, caso mude, altere em todos os lugares para não ter erros.

  • sensor.espn_futebol
  • sensor.espn_tabela

A parte de automações me avisem se esta ok para vocês, testem com times e jogos grandes pois nem todos os jogos estão dando dados ao vivo, talvez quando começar o brasileirão funcione bem.

Qualquer coisa postem ai. Abraço

1 Like

Também é possível baixar a integração da ESPN, porem ela e´ mais chatinha de mexer e alterar times. Mas e´ possível adicionar outros esportes.

1 Like

Não entendi como fazer o passo 4 e 5 :thinking:

O passo 4 para vc não ter que criar uma entidade ajudante chamada input_select.tabela_campeonatos você cria através do yaml, vai ter um arquivo que é input_select.yaml e você cola esse código que postei. Esse arquivo fica junto com os demais do HA, caso não exista você pode criar:

O mesmo vale para o passo 5, mas você pode criar uma entidade nos ajudantes chamada de input_text.espn_team e por o nome do time que você quer saber os dados

O passo 5 antes de você responder conseguir fazer, já o 4 fiz o que você informou e não esta funcionando, tive que criar e adicionar um por um la no ajudantes auxiliares.
A automação não funcionou pra mim, nos nós da alexa e telegram e necessário configurar algo mais?

Ajustando ainda as coias, mas esse novo tá muito top irmão…

Só n entendi o pq n buscou os dados da partida…

Boa mano, isso ai. Os dados não aparecem pq são campeonatos com “menos relevância” nem todos vão ter os dados. Faz um teste colocando u m real madrid, jogos como copa do brasil tem pego certinho

1 Like

Realmente a automação não funcionou aqui, testei com o jogo de Portugal e do brasil.

vou fazer um teste agora a tarde com esse jogo:

@PauloSantos chegou avisar que o jogo iria começar? Isso ele faz mesmo que os dados em tempo real não estejam disponiveis na partida

Não não @kelvinrafaeli, não notificou nada. Eu tinha te perguntado se precisava fazer alguma configuração a mais no telegram e alexa.

Na verdade essa parte de notificar, alexa e telegram vocês precisam adaptar para o uso de vocês. Como utilizo por subflow para utilizar em todas automações sem ter que repetir fluxo, para o meu uso já esta ok pois é um fluxo a parte que gerencia telegram e alexa.

Ou seja toda essa parte aqui que marquei vocês precisam adaptar para telegram/alexa/whatspp como preferirem

A alexa acredito que posso resolver, minha duvida fica enquanto ao telegram, como fazer pra receber e responder o YES. Tem algum tutorial aqui que ensine a fazer isso?

Peguei o jogo das eliminatórias e deu bom:

1 Like

Cara, eu acho que tem aqui no fórum um tutorial de telegram, tem que dar uma pesquisada ai de cabeça assim não sei te dizer. Tem tutoria do meu amigo @Choske no canal dele você encontra de tudo, segue ai que não tem erro:

1 Like

Campeonato Brasileiro ta 100% também…

1 Like