Boas malta, o anterior parser que tinha feito para obter os jogos de futebol com transmissão na TV deixou de funcionar e fiz outro apartir de outro site fonte.
Partilho o flow que fiz para obter um conjunto de dados como o card que fiz de forma a facilitar a leitura dos jogos entre os diferentes dias/competições.
O card tem vários buttons para selecionar o dia assim como o tipo de vista, para tal é necessário seguir as instruções na parte de configuração do card.
Devem instalar as seguintes bibliotecas no node red:
node-red-contrib-cron-plus
node-red-contrib-iconv
Flow a importar para o Node Red:
(devem configurar os nodes necessários de forma a executarem o flow e criar o sensor no Home Assistant)
[{"id":"30ee198fc9087217","type":"tab","label":"Futebol","disabled":false,"info":"","env":[]},{"id":"e01a42f439c105e8","type":"inject","z":"30ee198fc9087217","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":160,"wires":[["ac7e9165fbb8182e"]]},{"id":"ac7e9165fbb8182e","type":"http request","z":"30ee198fc9087217","name":"","method":"GET","ret":"bin","paytoqs":"ignore","url":"https://www.zerozero.pt/zapping","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":290,"y":160,"wires":[["e9e914a8d34f99f7"]]},{"id":"e9e914a8d34f99f7","type":"converter","z":"30ee198fc9087217","name":"","from":"ISO-8859-1","x":460,"y":160,"wires":[["2162710daca98e23"]]},{"id":"bb49728e0dd5d749","type":"debug","z":"30ee198fc9087217","name":"debug 12","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1160,"y":160,"wires":[]},{"id":"2162710daca98e23","type":"html","z":"30ee198fc9087217","name":"tbody","property":"payload","outproperty":"payload","tag":"#page_main > div:nth-child(2) > table > tbody","ret":"html","as":"single","x":610,"y":160,"wires":[["01ecd02c959eaef3"]]},{"id":"01ecd02c959eaef3","type":"function","z":"30ee198fc9087217","name":"Get table rows","func":"let allRows = [];\nlet html = msg.payload[0];\nlet htmlToParse = html;\n\nwhile(htmlToParse.indexOf(\"<tr>\") > -1 && htmlToParse.indexOf(\"</tr>\") > -1) {\n let currentRow = htmlToParse.substring(4, htmlToParse.indexOf(\"</tr>\"));\n\n allRows.push( {\n 'row': currentRow,\n });\n htmlToParse = htmlToParse.substring(htmlToParse.indexOf(\"</tr>\")+5, htmlToParse.length);\n} \n\n\nreturn [{\n 'payload': \n {\n 'allRows': allRows\n }\n}, null];","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":780,"y":160,"wires":[["a52ede8c0bbbfc24"]]},{"id":"a52ede8c0bbbfc24","type":"function","z":"30ee198fc9087217","name":"Get all games","func":"let allRows = msg.payload.allRows;\nlet games = [];\n\nlet remainingRow = null;\nlet urlBase = \"https://www.zerozero.pt\";\n\nvar date = new Date();\nvar dateStr =\n date.getFullYear()+ \"-\" +\n (\"00\" + (date.getMonth() + 1)).slice(-2) + \"-\" +\n (\"00\" + date.getDate()).slice(-2) + \" \" +\n (\"00\" + date.getHours()).slice(-2) + \":\" +\n (\"00\" + date.getMinutes()).slice(-2) + \":\" +\n (\"00\" + date.getSeconds()).slice(-2);\n\n\n\n\nfor (var i = 0; i < allRows.length; i++) {\n\n let row = allRows[i].row;\n let game = {\n 'date' : '',\n 'time' : '',\n 'transmissionType' : '',\n 'country' : '',\n 'countryIcon' : '',\n 'division' : '',\n 'homeTeamName' : '',\n 'homeTeamIcon' : '',\n 'awayTeamName' : '',\n 'awayTeamIcon' : '',\n 'channel' : '',\n 'channelIcon' : '',\n 'channelLink' : '',\n 'competitionName' : ''\n };\n\n if (game.date == '') {\n let gameTime = row.substring(row.indexOf(\";data=\") + 6, row.indexOf(\";data=\") + 25);\n game.date =gameTime.split(\" \")[0];\n game.time = gameTime.split(\" \")[1].substring(0, gameTime.split(\" \")[1].length - 3);\n row = row.substring(row.indexOf(\";data=\") + 25, row.length);\n\n remainingRow = row;\n }\n if (game.countryIcon == '') {\n game.countryIcon = urlBase + row.substring(row.indexOf(\"img src=\") + 9, row.indexOf(\"alt=\") - 25);\n game.country = row.substring(row.indexOf(\"alt=\") + 5, row.indexOf(\"title\") - 2);\n\n row = row.substring(row.indexOf(\"title\"), row.length);\n remainingRow = row;\n }\n\n if(game.division == '') {\n game.division = row.substring(0, row.indexOf(\"</a>\")).substring(row.substring(0, row.indexOf(\"</a>\")).lastIndexOf(\">\")+1,row.substring(0, row.indexOf(\"</a>\")).length);\n // game.division = game.division.substring(0, game.division.lastIndexOf(\" \"));\n row = row.substring(row.indexOf(\"</a>\"), row.length);\n remainingRow = row;\n }\n\n if(game.homeTeamName == '') {\n game.homeTeamName = hexHtmlToString(row.substring(row.indexOf(\"alt=\") + 5, row.indexOf(\"title\") - 2));\n game.homeTeamIcon = urlBase + row.substring(row.indexOf(\"src=\") + 5, row.indexOf(\"border=\") - 2);\n\n row = row.substring(row.indexOf(\"border=\")+10, row.length);\n remainingRow = row;\n\n game.awayTeamIcon = urlBase+ row.substring(row.indexOf(\"src=\") + 5, row.indexOf(\"border=\") - 2);\n row = row.substring(row.indexOf(\"vs\"), row.length);\n remainingRow = row;\n }\n\n if(game.awayTeamName == '') {\n game.awayTeamName = hexHtmlToString(row.substring( row.substring(0, row.indexOf(\"<span\")).lastIndexOf(\">\")+1, row.indexOf(\"<span\")));\n \n row = row.substring(row.indexOf('<span'), row.length);\n remainingRow = row;\n }\n\n if(game.channel == '') {\n if(row.indexOf(\"href=\") < row.indexOf(\"<img\")) {\n game.channelLink = row.substring(row.indexOf(\"href=\") + 6, row.indexOf(\"<img\") - 2);\n }\n \n game.channelIcon = getChannelLink(game);\n // urlBase+ row.substring(row.indexOf(\"src=\") + 5, row.indexOf(\"width=\")-2);\n game.channel = row.substring(row.indexOf(\"alt=\") + 5, row.indexOf(\"title\") - 2);\n game.competitionName = row.substring(row.substring(0, row.lastIndexOf(\"</a>\") - 2).lastIndexOf(\">\")+1, row.lastIndexOf(\"</a>\"));\n game.competitionName = game.competitionName.substring(0, game.competitionName.lastIndexOf(\" \"));\n \n if( game.channel == \"Canal11\"){\n game.channel = \"Canal 11\";\n game.channelIcon = \"https://www.canal11.pt/images/customer/logo.png\";\n } else if(game.channel.includes(\"11Sports\")) {\n game.channel = game.channel.replace(\"11Sports\", \"Eleven Sports\");\n \n } else if (game.channel == \"SporTtv+\") {\n game.channel = \"Sport TV +\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-mais-rebrand.svg\";\n \n\n } else if (game.channel == \"SportTv1\") {\n game.channel = \"Sport TV1\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-1-rebrand.svg\";\n \n\n } else if (game.channel == \"SportTv2\") {\n game.channel = \"Sport TV 2\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-2-rebrand.svg\";\n \n\n } else if (game.channel == \"SportTv3\") {\n game.channel = \"Sport TV 3\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-3-rebrand.svg\";\n \n\n } else if (game.channel == \"SportTv4\") {\n game.channel = \"Sport TV 4\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-4-rebrand.svg\";\n \n\n } else if (game.channel == \"SportTv5\") {\n game.channel = \"Sport TV 5\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-5-rebrand.svg\";\n\n } else if (game.channel == \"SportTv6\") {\n game.channel = \"Sport TV 6\";\n game.channelIcon = \"https://www.sporttv.pt/logos/sporttv-6-rebrand.svg\";\n } else if (game.channel == \"BTv\") {\n game.channel = \"Benfica TV\";\n game.channelIcon = \"https://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Logo_Benfica_TV.png/800px-Logo_Benfica_TV.png\";\n }\n \n if (game.channel === \"Eleven Sports 1\") {\n game.channelIcon = \"https://www.meo.pt/PublishingImages/canais/dazn-eleven-1-meo-logo.webp\";\n }\n if (game.channel === \"Eleven Sports 2\") {\n game.channelIcon = \"https://www.meo.pt/PublishingImages/canais/dazn-eleven-2-meo-logo.webp\";\n }\n if (game.channel === \"Eleven Sports 3\") {\n game.channelIcon = \"https://www.meo.pt/PublishingImages/canais/dazn-eleven-3-meo-logo.webp\";\n }\n if (game.channel == \"Eleven Sports 4\") {\n game.channelIcon = \"https://www.meo.pt/PublishingImages/canais/dazn-eleven-4-meo-logo.webp\";\n }\n if (game.channel == \"Eleven Sports 5\") {\n game.channelIcon = \"https://www.meo.pt/PublishingImages/canais/dazn-eleven-5-meo-logo.webp\";\n }\n if (game.channel == \"Eleven Sports 6\") {\n game.channelIcon = \"https://www.meo.pt/PublishingImages/canais/dazn-eleven-6-meo-logo.webp\";\n }\n\n if (game.channel == \"RTP1\") {\n game.channel = \"RTP 1\";\n game.channelIcon = \"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/RTP1_-_Logo_2016.svg/2560px-RTP1_-_Logo_2016.svg.png\";\n }\n\n if (game.channel == \"RTP Play\") {\n game.channelIcon = \"https://static.wikia.nocookie.net/logopedia/images/4/47/RTP_Play.svg/revision/latest?cb=20211109150238\";\n }\n\n if (game.channel == \"SIC\") {\n game.channelIcon = \"https://upload.wikimedia.org/wikipedia/pt/5/51/Logo_SIC_2018.png\";\n }\n\n if (game.channel == \"TVI\") {\n game.channelIcon = \"https://upload.wikimedia.org/wikipedia/en/6/63/TVI_logo_2017.png\";\n }\n\n if(game.channel == \"AFL TV\") {\n game.channelIcon = \"https://afl.pt/wp-content/uploads/2023/10/AFL-TV__.png\";\n }\n\n \n\n \n\n \n }\n games.push(game);\n}\n\nfunction getChannelLink(game) {\n let channelLink = \"\";\n\n if(game.channel == \"Eleven Sports 4\") {\n channelLink = \"canais/dazn-eleven-4-meo-logo.webp\";\n }\n \n return channelLink;\n}\n\nfunction hexHtmlToString(str) {\n if (str.includes(\"ç\")) {\n str = str.replace(\"ç\", \"ç\");\n }\n\n if (str.includes(\"á\")) {\n str = str.replace(\"á\", \"á\");\n }\n\n if (str.includes(\"ã\")) {\n str = str.replace(\"ã\", \"ã\");\n }\n\n if (str.includes(\"é\")) {\n str = str.replace(\"é\", \"é\");\n }\n\n\n if (str.includes(\"ó\")) {\n str = str.replace(\"ó\", \"ó\");\n }\n\n \n \n return str;\n}\n\nfunction getTodayGames(gamesByDate) {\n let today = new Date().toISOString().split('T')[0];\n let todayGames = [];\n for(var i=0; i<gamesByDate.length; i++) {\n if(gamesByDate[i].date == today) {\n todayGames = gamesByDate[i];\n break;\n }\n }\n return todayGames;\n}\n\nfunction getTomorrowGames(gamesByDate) {\n var tomorrowDate = new Date();\n tomorrowDate.setDate(tomorrowDate.getDate() + 1);\n tomorrowDate = tomorrowDate.toISOString().split('T')[0];\n\n let tomorrowGames = [];\n for(var i=0; i<gamesByDate.length; i++) {\n if(gamesByDate[i].date == tomorrowDate) {\n tomorrowGames = gamesByDate[i];\n break;\n }\n }\n return tomorrowGames;\n}\n\nfunction getNextThreeDaysGames(gamesByDate) {\n let nextThreeDays = [];\n let today = new Date().toISOString().split('T')[0];\n nextThreeDays.push(today);\n\n var tomorrowDate = new Date();\n tomorrowDate.setDate(tomorrowDate.getDate() + 1);\n tomorrowDate = tomorrowDate.toISOString().split('T')[0];\n nextThreeDays.push(tomorrowDate);\n\n var nextTomorrowDate = new Date();\n nextTomorrowDate.setDate(nextTomorrowDate.getDate() + 2);\n nextTomorrowDate = nextTomorrowDate.toISOString().split('T')[0];\n nextThreeDays.push(nextTomorrowDate);\n\n let nextThreeDaysGames = [];\n for(var i=0; i<gamesByDate.length; i++) {\n if(nextThreeDays.includes(gamesByDate[i].date)) {\n nextThreeDaysGames.push(gamesByDate[i]);\n }\n }\n return nextThreeDaysGames;\n}\n\n\n\n\nfunction getGamesByDate(allGames) {\n let gamesByDate = [];\n for(var i=0; i<allGames.length; i++) {\n if(gamesByDate.length ==0) {\n gamesByDate.push({\n 'date' : allGames[i].date,\n 'games' : [allGames[i]],\n 'competitions' : [{\n 'name' : allGames[i].competitionName,\n 'icon': allGames[i].countryIcon,\n 'games' : [allGames[i]]\n }\n ]\n });\n } else {\n let foundedDate = false;\n let foundedCompetition = false;\n for (var t = 0; t < gamesByDate.length; t++) {\n if (gamesByDate[t].date == allGames[i].date) {\n foundedDate = true;\n gamesByDate[t].games.push(allGames[i]);\n for(var x=0; x<gamesByDate[t].competitions.length; x++) {\n if(gamesByDate[t].competitions[x].name ==allGames[i].competitionName ) {\n gamesByDate[t].competitions[x].games.push(allGames[i]);\n foundedCompetition = true;\n }\n }\n if(!foundedCompetition) {\n gamesByDate[t].competitions.push({\n 'name' : allGames[i].competitionName,\n 'icon' : allGames[i].countryIcon,\n 'games' : [allGames[i]]\n });\n }\n }\n }\n if(!foundedDate) {\n gamesByDate.push({\n 'date' : allGames[i].date,\n 'games' : [allGames[i]],\n 'competitions' : [{\n 'name' : allGames[i].competitionName,\n 'icon' : allGames[i].countryIcon,\n 'games' : [allGames[i]]\n }\n ]\n });\n }\n }\n }\n return gamesByDate;\n}\n\nlet gamesByDate = getGamesByDate(games);\nlet todayGames = getTodayGames(gamesByDate);\nlet tomorrowGames = getTomorrowGames(gamesByDate);\nlet nextThreeDaysGames = getNextThreeDaysGames(gamesByDate);\n\nreturn [{\n 'payload': {\n 'updatedOn' : dateStr,\n 'allGames': games,\n 'gamesByDate' : gamesByDate,\n 'todayGames' : todayGames,\n 'tomorrowGames' : tomorrowGames,\n 'nextThreeDaysGames' : nextThreeDaysGames\n }\n}, null];","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":980,"y":160,"wires":[["bb49728e0dd5d749","956c0583d750ed41"]]},{"id":"956c0583d750ed41","type":"ha-sensor","z":"30ee198fc9087217","name":"TV FootbalGames","entityConfig":"c5c174550c444990","version":0,"state":"payload.updatedOn","stateType":"msg","attributes":[{"property":"todayGames","value":"payload.todayGames","valueType":"msg"},{"property":"tomorrowGames","value":"payload.tomorrowGames","valueType":"msg"},{"property":"updatedOn","value":"payload.updatedOn","valueType":"msg"},{"property":"nextThreeDaysGames","value":"payload.nextThreeDaysGames","valueType":"msg"},{"property":"gamesByDate","value":"payload.gamesByDate","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":1190,"y":260,"wires":[[]]},{"id":"70ab84cc965c1022","type":"cronplus","z":"30ee198fc9087217","name":"Every hour","outputField":"payload","timeZone":"","storeName":"","commandResponseMsgOutput":"output1","defaultLocation":"","defaultLocationType":"default","outputs":1,"options":[{"name":"schedule1","topic":"topic1","payloadType":"default","payload":"","expressionType":"cron","expression":"0 0 * * * *","location":"","offset":"0","solarType":"all","solarEvents":"sunrise,sunset"}],"x":150,"y":60,"wires":[["ac7e9165fbb8182e"]]},{"id":"c5c174550c444990","type":"ha-entity-config","server":"b9ae8401.4dfb28","deviceConfig":"","name":"TV Footbal Games","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"TV Footbal Games"},{"property":"icon","value":"mdi:soccer"},{"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":"b9ae8401.4dfb28","type":"server","name":"Home Assistant","addon":true}]
Devem testar a execução do flow para garantir que o sensor é criado com sucesso. O sensor criado tem o nome sensor.tv_footbal_games. Para validar, podem aceder ao Developer Tools e consultar o estado do sensor anterior para garantir que os dados foram carregados com sucesso.
Devem criar o seguinte template no ficheiro configuration.yaml
template:
- sensor:
- name: "Football TV Selected View Type"
state: >
{% if is_state('input_text.football_tv_range_days', 'today') and
is_state('input_text.football_tv_view_type', 'grid') %}
today_grid
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'today') and
is_state('input_text.football_tv_view_type', 'list') %}
today_list
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'tomorrow') and
is_state('input_text.football_tv_view_type', 'grid') %}
tomorrow_grid
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'tomorrow') and
is_state('input_text.football_tv_view_type', 'list') %}
tomorrow_list
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'nextdays') and
is_state('input_text.football_tv_view_type', 'grid') %}
nextdays_grid
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'nextdays') and
is_state('input_text.football_tv_view_type', 'list') %}
nextdays_list
{% endif %}
A nivel do card, é necessário adicionarem os seguintes cards custom:
Para o card, criei 2 inputs helpers (aceder às Settings, integrations, helpers e criar com os nomes iguais) que permite guardar a selecção do dia e tipo de vista.
Criar dois helpers com os ids:
input_text.football_tv_view_type e input_text.football_tv_range_days
Código do Card:
type: custom:vertical-stack-in-card
cards:
- type: custom:bootstrap-grid-card
cards:
- type: row
cards:
- type: custom:button-card
class: col-xs-3 col-md-1 col-2 col-lg-1
icon: mdi:calendar-today
size: 60%
styles:
card:
- height: 30px
tap_action:
action: call-service
service: input_text.set_value
target:
entity_id: input_text.football_tv_range_days
data:
value: today
- type: custom:button-card
class: col-xs-3 col-md-2 col-2 col-lg-1
icon: mdi:calendar-arrow-right
size: 60%
styles:
card:
- height: 30px
tap_action:
action: call-service
service: input_text.set_value
target:
entity_id: input_text.football_tv_range_days
data:
value: tomorrow
- type: custom:button-card
class: col-xs-3 col-md-2 col-2 col-lg-1
icon: mdi:calendar-end
size: 60%
styles:
card:
- height: 30px
tap_action:
action: call-service
service: input_text.set_value
target:
entity_id: input_text.football_tv_range_days
data:
value: nextdays
- type: custom:button-card
color_type: blank-card
class: col-xs-3 col-md-5 col-2 col-lg-7
- type: custom:button-card
class: col-xs-10 col-md-1 col-2 col-lg-1
icon: mdi:format-list-bulleted
size: 60%
styles:
card:
- height: 30px
tap_action:
action: call-service
service: input_text.set_value
target:
entity_id: input_text.football_tv_view_type
data:
value: list
- type: custom:button-card
class: col-xs-10 col-md-1 col-2 col-lg-1
size: 60%
styles:
card:
- height: 30px
tap_action:
action: call-service
service: input_text.set_value
target:
entity_id: input_text.football_tv_view_type
data:
value: grid
icon: mdi:order-bool-ascending
- type: vertical-stack
cards:
- type: conditional
conditions:
- entity: sensor.football_tv_selected_view_type
state: today_list
card:
type: custom:html-template-card
ignore_line_breaks: true
content: |
<h2> Futebol na TV: <u>
{{states.sensor.tv_footbal_games.attributes.todaygames.date }}</u>
</h2>
<table style="width: 100%; border: 1px solid; border-radius: 10px;">
<tbody>
{% for game in states.sensor.tv_footbal_games.attributes.todaygames.games -%}
<tr>
<td colspan="4" style=" text-align:center;"><img style=margin-top:10px;margin-right:10px;width:20px;border-radius:50px;height:20px" src={{game.countryIcon}} /><b>{{game.competitionName}} </b></td>
<tr>
<td style="font-size:10px;text-align:center; width:10%">{{game.time}}</td>
<td> <div style="margin-left:10px;border-left:1px solid;height:30px"></div></td>
<td >
<div style="margin-top:10px; margin-bottom:5px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.homeTeamIcon}} /><label style="margin-left:10px">{{game.homeTeamName}} </label> </div>
<div style="margin-bottom:10px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.awayTeamIcon}} /><label style="margin-left:10px">{{game.awayTeamName}} </label> </div>
</td>
<td style="width:20%; text-align:center">
<div ><img
style="max-height:30px; max-width:70px; height:auto;width:auto;"
src={{game.channelIcon}} /><div>
<div style="font-size:8px;">{{game.channel}}</div>
</td>
</tr>
{%- endfor %} <tbody> </table>
- type: conditional
conditions:
- entity: sensor.football_tv_selected_view_type
state: today_grid
card:
type: custom:html-template-card
title: null
ignore_line_breaks: true
content: >
<h2> Futebol na TV: <u>
{{states.sensor.tv_footbal_games.attributes.todaygames.date }}</u>
</h2>
{% for competition in states.sensor.tv_footbal_games.attributes.todaygames.competitions -%}
<table style="margin-top:15px; width: 100%; border: 1px solid; border-radius: 10px;">
<tbody>
<tr>
<td colspan="4" style=" text-align:center;"><img style=margin-top:10px;margin-right:10px;width:20px;border-radius:50px;height:20px" src={{competition.icon}} /><b>{{competition.name}} </b></td>
</tr>
{% for game in competition.games -%}
<tr>
<td style="font-size:10px;text-align:center; width:10%">{{game.time}}</td>
<td> <div style="margin-left:10px;border-left:1px solid;height:30px"></div></td>
<td >
<div style="margin-top:10px; margin-bottom:5px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.homeTeamIcon}} /><label style="margin-left:10px">{{game.homeTeamName}} </label> </div>
<div style="margin-bottom:10px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.awayTeamIcon}} /><label style="margin-left:10px">{{game.awayTeamName}} </label> </div>
</td>
<td style="width:20%;text-align:center">
<div ><img
style="max-height:30px; max-width:70px; height:auto;width:auto;"
src={{game.channelIcon}} /><div>
<div style="font-size:8px;">{{game.channel}}</div>
</td>
</tr>
{%- endfor %}
<tbody> </table> {%- endfor %}
- type: conditional
conditions:
- entity: sensor.football_tv_selected_view_type
state: tomorrow_list
card:
type: custom:html-template-card
ignore_line_breaks: true
content: |
<h2> Futebol na TV: <u>
{{states.sensor.tv_footbal_games.attributes.tomorrowgames.date }}</u>
</h2>
<table style="width: 100%; border: 1px solid; border-radius: 10px;">
<tbody>
{% for game in states.sensor.tv_footbal_games.attributes.tomorrowgames.games -%}
<tr>
<td colspan="4" style=" text-align:center;"><img style=margin-top:10px;margin-right:10px;width:20px;border-radius:50px;height:20px" src={{game.countryIcon}} /><b>{{game.competitionName}} </b></td>
<tr>
<td style="font-size:10px;text-align:center; width:10%">{{game.time}}</td>
<td> <div style="margin-left:10px;border-left:1px solid;height:30px"></div></td>
<td >
<div style="margin-top:10px; margin-bottom:5px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.homeTeamIcon}} /><label style="margin-left:10px">{{game.homeTeamName}} </label> </div>
<div style="margin-bottom:10px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.awayTeamIcon}} /><label style="margin-left:10px">{{game.awayTeamName}} </label> </div>
</td>
<td style="width:20%;text-align:center">
<div ><img
style="max-height:30px; max-width:70px; height:auto;width:auto;"
src={{game.channelIcon}} /><div>
<div style="font-size:8px;">{{game.channel}}</div>
</td>
</tr>
{%- endfor %} <tbody> </table>
- type: conditional
conditions:
- entity: sensor.football_tv_selected_view_type
state: tomorrow_grid
card:
type: custom:html-template-card
ignore_line_breaks: true
content: >
<h2> Futebol na TV: <u>
{{states.sensor.tv_footbal_games.attributes.tomorrowgames.date
}}</u> </h2>
{% for competition in states.sensor.tv_footbal_games.attributes.tomorrowgames.competitions -%}
<table style="margin-top:15px; width: 100%; border: 1px solid; border-radius: 10px;">
<tbody>
<tr>
<td colspan="4" style=" text-align:center;"><b>{{competition.name}} </b></td>
</tr>
{% for game in competition.games -%}
<tr>
<td style="font-size:10px;text-align:center; width:10%">{{game.time}}</td>
<td> <div style="margin-left:10px;border-left:1px solid;height:30px"></div></td>
<td >
<div style="margin-top:10px; margin-bottom:5px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.homeTeamIcon}} /><label style="margin-left:10px">{{game.homeTeamName}} </label> </div>
<div style="margin-bottom:10px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.awayTeamIcon}} /><label style="margin-left:10px">{{game.awayTeamName}} </label> </div>
</td>
<td style="width:20%;text-align:center">
<div ><img
style="max-height:30px; max-width:70px; height:auto;width:auto;"
src={{game.channelIcon}} /><div>
<div style="font-size:8px;">{{game.channel}}</div>
</td>
</tr>
{%- endfor %}
<tbody> </table> {%- endfor %}
- type: conditional
conditions:
- entity: sensor.football_tv_selected_view_type
state: nextdays_list
card:
type: custom:html-template-card
ignore_line_breaks: true
content: >
{% for gameDate in
states.sensor.tv_footbal_games.attributes.gamesbydate -%}
<h2>{{gameDate.date}}</h2>
<table style="width: 100%; border: 1px solid; border-radius: 10px;">
<tbody>
{% for game in gameDate.games -%}
<tr>
<td colspan="4" style=" text-align:center;"><img style=margin-top:10px;margin-right:10px;width:20px;border-radius:50px;height:20px" src={{game.countryIcon}} /><b>{{game.competitionName}} </b></td>
<tr>
<td style="font-size:10px;text-align:center; width:10%">{{game.time}}</td>
<td> <div style="margin-left:10px;border-left:1px solid;height:30px"></div></td>
<td >
<div style="margin-top:10px; margin-bottom:5px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.homeTeamIcon}} /><label style="margin-left:10px">{{game.homeTeamName}} </label> </div>
<div style="margin-bottom:10px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.awayTeamIcon}} /><label style="margin-left:10px">{{game.awayTeamName}} </label> </div>
</td>
<td style="width:20%;text-align:center">
<div ><img
style="max-height:30px; max-width:70px; height:auto;width:auto;"
src={{game.channelIcon}} /><div>
<div style="font-size:8px;">{{game.channel}}</div>
</td>
</tr>
{%- endfor %}
<tbody> </table>
{%- endfor %}
- type: conditional
conditions:
- entity: sensor.football_tv_selected_view_type
state: nextdays_grid
card:
type: custom:html-template-card
ignore_line_breaks: true
content: |
{% for gameDate in
states.sensor.tv_footbal_games.attributes.gamesbydate -%}
<h2>{{gameDate.date}}</h2>
{% for competition in gameDate.competitions -%}
<table style="margin-top:15px; width: 100%; border: 1px solid; border-radius: 10px;">
<tbody>
<tr>
<td colspan="4" style=" text-align:center;"><b>{{competition.name}} </b></td>
</tr>
{% for game in competition.games -%}
<tr>
<td style="font-size:10px;text-align:center; width:10%">{{game.time}}</td>
<td> <div style="margin-left:10px;border-left:1px solid;height:30px"></div></td>
<td >
<div style="margin-top:10px; margin-bottom:5px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.homeTeamIcon}} /><label style="margin-left:10px">{{game.homeTeamName}} </label> </div>
<div style="margin-bottom:10px"><img style="vertical-align:middle;width:20px;height:20px" src={{game.awayTeamIcon}} /><label style="margin-left:10px">{{game.awayTeamName}} </label> </div>
</td>
<td style="width:20%;text-align:center">
<div ><img
style="max-height:30px; max-width:70px; height:auto;width:auto;"
src={{game.channelIcon}} /><div>
<div style="font-size:8px;">{{game.channel}}</div>
</td>
</tr>
{%- endfor %}
</table>
{%- endfor %}
{%- endfor %}
Além disto é preciso criar o seguinte sensor no ficheiro configuration.yaml para guardar a seleção referente ao tipo de vista/dia.
template:
- sensor:
- name: "Football TV Selected View Type"
state: >
{% if is_state('input_text.football_tv_range_days', 'today') and
is_state('input_text.football_tv_view_type', 'grid') %}
today_grid
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'today') and
is_state('input_text.football_tv_view_type', 'list') %}
today_list
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'tomorrow') and
is_state('input_text.football_tv_view_type', 'grid') %}
tomorrow_grid
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'tomorrow') and
is_state('input_text.football_tv_view_type', 'list') %}
tomorrow_list
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'nextdays') and
is_state('input_text.football_tv_view_type', 'grid') %}
nextdays_grid
{% endif %}
{% if is_state('input_text.football_tv_range_days', 'nextdays') and
is_state('input_text.football_tv_view_type', 'list') %}
nextdays_list
{% endif %}