Using (JSON) output from Pyscript

hi all - not sure where to put then question but here goes: I’m trying to get the output of a python script, executed by pyscript, for use in HASS. Specifically, I want to be able to use the JSON output from the script below in automation / Lovelace.

The script seems to work but I can’t access any attributes of the output. I’m a total noob so apologies if this is extremely dumb.

@service
def goatrock_tides(supports_response="only"):
  import aiohttp
  import asyncio
  from bs4 import BeautifulSoup
  import json

  async def fetch_data(url, headers=None):
      async with aiohttp.ClientSession() as session:
          async with session.get(url, headers=headers) as response:
              return await response.text()

  async def main():
      # URL of the web page containing the table
      url = 'https://www.tideschart.com/United-States/California/Sonoma-County/Goat-Rock-Beach/Weekly/'
    
      # Define headers (if needed)
      headers = {
          'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36',
          'Accept-Language': 'en-US,en;q=0.9',
    }

      # Fetch the web page content asynchronously with headers
      html_content = await fetch_data(url, headers=headers)

      # Parse the HTML content using BeautifulSoup
      soup = BeautifulSoup(html_content, 'html.parser')

      # Find the table element with the specified class
      table = soup.find('table', class_='table table-hover tidechart mb-4')

      # Initialize an empty list to store the table data
      table_data = []

      # Find all rows within the table body
      rows = table.tbody.find_all('tr')

      # Loop through each row and extract the data
      for row in rows:
          columns = row.find_all('td')
          day = columns[0].text.strip()
          first_tide = columns[1].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          second_tide = columns[2].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          third_tide = columns[3].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          fourth_tide = columns[4].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          sunrise = columns[5].text.strip().replace('\u25b2', '').replace('\u25bC', '').replace(' ', '')
          sunset = columns[6].text.strip().replace('\u25b2', '').replace('\u25bC', '').replace(' ', '')

          # Create a dictionary for the current row
          row_data = {
              "Day": day,
              "1st Tide": first_tide,
              "2nd Tide": second_tide,
              "3rd Tide": third_tide,
              "4th Tide": fourth_tide,
              "Sunrise": sunrise,
              "Sunset": sunset
      }

          # Append the row data to the list
          table_data.append(row_data)

      # Convert the table data list to JSON
      json_output = json.dumps(table_data, indent=4)

      # Print or save the JSON data as needed
      print(json_output)

  if __name__ == '__main__':
      asyncio.run(main())

You could set the value into a sensor. like at Value_template for XML Reading - #10 by Zufan81

1 Like

No luck… updated my configuration.yaml to enable logging and updated the script to the following but no sign of it in the home assistant core logs, calling pyscript.goatrock_tides as a service doesn’t return anything, no sensor is created… help?

@service
def goatrock_tides():
  import aiohttp
  import asyncio
  from bs4 import BeautifulSoup
  import json

  async def fetch_data(url, headers=None):
      async with aiohttp.ClientSession() as session:
          async with session.get(url, headers=headers) as response:
              return await response.text()

  async def main():
      # URL of the web page containing the table
      url = 'https://www.tideschart.com/United-States/California/Sonoma-County/Goat-Rock-Beach/Weekly/'
    
      # Define headers (if needed)
      headers = {
          'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36',
          'Accept-Language': 'en-US,en;q=0.9',
    }

      # Fetch the web page content asynchronously with headers
      html_content = await fetch_data(url, headers=headers)

      # Parse the HTML content using BeautifulSoup
      soup = BeautifulSoup(html_content, 'html.parser')

      # Find the table element with the specified class
      table = soup.find('table', class_='table table-hover tidechart mb-4')

      # Initialize an empty list to store the table data
      table_data = []

      # Find all rows within the table body
      rows = table.tbody.find_all('tr')

      # Loop through each row and extract the data
      for row in rows:
          columns = row.find_all('td')
          day = columns[0].text.strip()
          first_tide = columns[1].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          second_tide = columns[2].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          third_tide = columns[3].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          fourth_tide = columns[4].text.strip().replace('\u25BC', ',').replace('\u25B2', ',')
          sunrise = columns[5].text.strip().replace('\u25b2', '').replace('\u25bC', '').replace(' ', '')
          sunset = columns[6].text.strip().replace('\u25b2', '').replace('\u25bC', '').replace(' ', '')

          # Create a dictionary for the current row
          row_data = {
              "Day": day,
              "1st Tide": first_tide,
              "2nd Tide": second_tide,
              "3rd Tide": third_tide,
              "4th Tide": fourth_tide,
              "Sunrise": sunrise,
              "Sunset": sunset
      }

          # Append the row data to the list
          table_data.append(row_data)

      # Convert the table data list to JSON
      json_output = json.dumps(table_data, indent=4)

      # Print or save the JSON data as needed
      log.info(json_output)
      sensor.goat_tides = json_output

  if __name__ == '__main__':
      asyncio.run(main())

I’m a noob here, but are you sure this way it gets executed at all?

So far I’ve just seen people using task.executor for pyscript stuff.

I’ve some running code where I define functions with @pyscript_compile and then pass them to the executor
such as

@pyscript_compile
def scrape_id_ultimo_listino():

  from bs4 import BeautifulSoup
  from urllib.request import urlopen

  with urlopen(...) as response:
    soup = BeautifulSoup(response, 'html.parser')
    return max(map(lambda a: int(a.get('href', '/').split('/')[-1]), soup.select('a[href^=".../"] ')))

@service
def update_id_ultimo_listino():
  id_ultimo_listino = task.executor(scrape_id_ultimo_listino)
  sensor.id_ultimo_listino = id_ultimo_listino