Custom component. How to implement scan_interval?

I’ve write a custom component for upcoming media card. Try to add scan_interval, but don’t understand how. When i simply add it to my code, then card appear when HA boot after the time is set in it. I want to sensor start after boot and then update goes like scan interval set.
This is code

"""Platform for sensor integration."""
import logging
from datetime import datetime, timedelta
from bs4 import BeautifulSoup
from urllib import request

#import asyncio
#import async_timeout

import requests
import json
import re
import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.components.switch import PLATFORM_SCHEMA
from homeassistant.const import *


DEFAULT_NAME = "teleman"




PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
#    vol.Required(CONF_TOKEN): cv.string,
#    vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.string,
#    vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
#    vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTO): cv.string,
#    vol.Optional(CONF_MAXIMUM, default=DEFAULT_LIMIT): cv.string,
#    vol.Optional(CONF_STATE, default=DEFAULT_STATE): cv.string,
     vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
#    vol.Optional(CONF_SORTING, default=DEFAULT_SORTING): cv.string
})


def setup_platform(hass, config, add_entities, discovery_info=None):
    add_entities([telemansensor(config)])

#SCAN_INTERVAL = timedelta(minutes=30)

class telemansensor(Entity):
    """Representation of a Sensor."""

    def __init__(self, config):
        self._state = None
        self._name = config.get(CONF_NAME)
        #self.token = config.get(CONF_TOKEN)
        #self.host = config.get(CONF_HOST)
        #self.protocol = config.get(CONF_PROTOCOL)
        #self.port = config.get(CONF_PORT)
        self.data = None
        #self.state_movies = config.get(CONF_STATE)
        #self.limit = config.get(CONF_MAXIMUM)
        #self.sort = config.get(CONF_SORTING)

    @property
    def name(self):
        """Return the name of the sensor."""
        return self._name

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def device_state_attributes(self):
        """Return the state attributes."""
        return self.data

    def update(self):
    #async def async_update(self):

        attributes = {}
        card_json = []
        movie_tab = []
        init = {}
        """Initialized JSON Object"""
        init['title_default'] = '$title'
        init['line1_default'] = '$studio'
        init['line2_default'] = '$release'
        init['line3_default'] = '$number - $rating - $runtime'
        init['line4_default'] = '$genres'
        init['icon'] = 'mdi:eye-off'
        card_json.append(init)
        
        page_url = 'https://m.teleman.pl/highlights'
        page = requests.get(page_url)
        soup = BeautifulSoup(page.content, 'html.parser')
        suggestions_div= soup.find(class_="suggestions")
        
        for link in suggestions_div.find_all('a'):
            href_link = link.get('href')
            inner_url = href_link.replace("/", "https://m.teleman.pl/", 1)
            data_movie = link.find('div', class_="time").get_text().strip().split(":")
            propper_hour = int(data_movie[0])
            propper_minute = int(data_movie[1])
            
            channel = link.find('div', class_="station").get_text().strip()
            
            #zaglądam do linku
            page_inner = requests.get(inner_url)
            soup_inner = BeautifulSoup(page_inner.content, 'html.parser')
            titlemovie = soup_inner.find('h2').get_text().strip()
            genre = soup_inner.find('div', class_="genre").get_text().strip()
            short_description = soup_inner.find('p', class_='show-desc').get_text().strip()
            image = soup_inner.find('img', itemprop="image").get('src')
            image_propper = image.replace("//", "https://", 1)
        
            card_items = {}
            #card_items['airdate'] = datetime.today().replace(microsecond=0).isoformat() +"Z"
            card_items['airdate'] = datetime.now().replace(hour=propper_hour, minute=propper_minute, microsecond=0).isoformat() +"Z"
            card_items['poster'] = image_propper
            card_items['title'] = titlemovie
            card_items['studio'] = channel
            card_items['release'] = "$day $time"
            movie_tab.append(card_items)
            
            #if self.sort == "date":
        movie_tab.sort(key=lambda x: x.get('airdate'))

        card_json = card_json + movie_tab
        attributes['data'] = json.dumps(card_json)
        self.data = attributes


1 Like

You should have a separate file which registers sensor platform, probably through the init file. Moreover, you should use coordinator as a best practice which will handle all update functionality from one central place and all your sensors can read it from coordinator internal state

1 Like

some example code link?

1 Like

PR to core: https://github.com/home-assistant/core/pull/62451

related custom integration: Kia Uvo Integration

1 Like

Also call your update like this, then it is async.
Import this:

from homeassistant.helpers.event import async_track_time_interval

This would go in init on your telemansensor class.

# Poll for updates in the background
    update_track = async_track_time_interval(
        hass,
        lambda now: this.update(),
        timedelta(
            seconds=60)
        ),
    )

i’m having a bit of a hard time fully comprehending this. I have been messing around with my own component and have the entire implementation in sensor.py. I want to limit the API calls from my update function, since it’s happening so frequently. Similar to @scalpel if I put SCAN_INTERVAL at the top it prevents the update at boot as well. I’d like to boot normally and allow this to take place post boot. Is it possible to implement this in sensory.py?