PiAware Monitoring msg/s and number of aircrafts (all/position/mlat)

Hi I tried to get some data by PiAware monitoring but it didn’t work well so I decided to do it by myself.

configuration.yaml:

rest:
  - resource: http://piaware/status.json
    scan_interval: 300
    sensor:
      - name: Piaware Status
        value_template: "OK"
        json_attributes:
          - "modes_enabled"
          - "site_url"
          - "piaware"
          - "uat_enabled"
          - "adept"
          - "mlat"
          - "piaware_version"
          - "radio"
  - resource: http://piaware/skyaware/data/aircraft.json
    scan_interval: 300
    sensor:
      - name: Piaware Aircraft
        value_template: "OK"
        json_attributes:
          - "now"
          - "messages"

sensor:
  - platform: template
    sensors:
      piaware_msgs_per_second:
        friendly_name: "PiAware Ilość wiadomości/s"
        unique_id: "piaware_msgs_per_second"
        unit_of_measurement: "msg/sec"
        value_template: >
          {% set messages = state_attr('sensor.piaware_aircraft', 'messages') | float(0) %}
          {% set var_now = state_attr('sensor.piaware_aircraft', 'now') | float(0) %}
          {% set last_messages = state_attr('sensor.piaware_msgs_per_second', 'last_messages') | float(0) %}
          {% set last_now = state_attr('sensor.piaware_msgs_per_second', 'last_now') | float(0) %}
          {% set last_rate = states('sensor.piaware_msgs_per_second') | float(0) %}
          {% if messages > 0 and var_now > 0 and last_now > 0 and last_messages > 0 %}
            {% set delta_messages = messages - last_messages %}
            {% set delta_time = var_now - last_now %}
            {% if delta_time > 0 and delta_messages > 0 %}
              {{ (delta_messages / delta_time) | round(1) }}
            {% else %}
              {% if last_rate > 0 %}
                {{ last_rate }}
              {% else %}
                0
              {% endif %}
            {% endif %}
          {% else %}
            {% if last_rate > 0 %}
              {{ last_rate }}
            {% else %}
              0
            {% endif %}
          {% endif %}
        attribute_templates:
          last_messages: >
            {% set current_messages = state_attr('sensor.piaware_aircraft', 'messages') | float(0) %}
            {% if current_messages > 0 %}
              {{ current_messages }}
            {% else %}
              {% set last_messages = state_attr('sensor.piaware_msgs_per_second', 'last_messages') | float(0) %}
              {{ last_messages }}
            {% endif %}
          last_now: >
            {% set current_now = state_attr('sensor.piaware_aircraft', 'now') | float(0) %}
            {% if current_now > 0 %}
              {{ current_now }}
            {% else %}
              {% set last_now = state_attr('sensor.piaware_msgs_per_second', 'last_now') | float(0) %}
              {{ last_now }}
            {% endif %}
      piaware_status_1090_radio:
        friendly_name: "Piaware 1090 Radio"
        value_template: "{{ state_attr('sensor.piaware_status', 'radio')['status'] }}"
        icon_template: >
          {% if state_attr('sensor.piaware_status', 'radio')['status'] == 'green' %}
            mdi:check-circle
          {% elif state_attr('sensor.piaware_status', 'radio')['status'] in ['yellow', 'orange'] %}
            mdi:alert-circle
          {% elif state_attr('sensor.piaware_status', 'radio')['status'] == 'red' %}
            mdi:close-circle
          {% else %}
            mdi:help-circle
          {% endif %}
        attribute_templates:
          message: "{{ state_attr('sensor.piaware_status', 'radio')['message'] }}"
      piaware_status_daemon:
        friendly_name: "Piaware Daemon"
        value_template: "{{ state_attr('sensor.piaware_status', 'piaware')['status'] }}"
        icon_template: >
          {% if state_attr('sensor.piaware_status', 'piaware')['status'] == 'green' %}
            mdi:check-circle
          {% elif state_attr('sensor.piaware_status', 'piaware')['status'] in ['yellow', 'orange'] %}
            mdi:alert-circle
          {% elif state_attr('sensor.piaware_status', 'piaware')['status'] == 'red' %}
            mdi:close-circle
          {% else %}
            mdi:help-circle
          {% endif %}
        attribute_templates:
          message: "{{ state_attr('sensor.piaware_status', 'piaware')['message'] }}"
      piaware_status_connection:
        friendly_name: "Piaware Connection"
        value_template: "{{ state_attr('sensor.piaware_status', 'adept')['status'] }}"
        icon_template: >
          {% if state_attr('sensor.piaware_status', 'adept')['status'] == 'green' %}
            mdi:check-circle
          {% elif state_attr('sensor.piaware_status', 'adept')['status'] in ['yellow', 'orange'] %}
            mdi:alert-circle
          {% elif state_attr('sensor.piaware_status', 'adept')['status'] == 'red' %}
            mdi:close-circle
          {% else %}
            mdi:help-circle
          {% endif %}
        attribute_templates:
          message: "{{ state_attr('sensor.piaware_status', 'adept')['message'] }}"
      piaware_status_mlat:
        friendly_name: "Piaware MLAT"
        value_template: "{{ state_attr('sensor.piaware_status', 'mlat')['status'] }}"
        icon_template: >
          {% if state_attr('sensor.piaware_status', 'mlat')['status'] == 'green' %}
            mdi:check-circle
          {% elif state_attr('sensor.piaware_status', 'mlat')['status'] in ['yellow', 'orange'] %}
            mdi:alert-circle
          {% elif state_attr('sensor.piaware_status', 'mlat')['status'] == 'red' %}
            mdi:close-circle
          {% else %}
            mdi:help-circle
          {% endif %}
        attribute_templates:
          message: "{{ state_attr('sensor.piaware_status', 'mlat')['message'] }}"

I wrote a simple Pyscript to track how many aircrafts, aircrafts with positions, or MLAT aircrafts are currently visible (the rest service is useless for this - too much data):

import aiohttp


def set_default_sensors():
    default_sensors = [
        ("sensor.aircraft_count", "Ilość wszystkich samolotów", "mdi:airplane"),
        (
            "sensor.aircraft_with_position_count",
            "Ilość samolotów ze znaną pozycją",
            "mdi:map-marker",
        ),
        (
            "sensor.aircraft_with_mlat_position_count",
            "Ilość samolotów z pozycją z mlat",
            "mdi:radar",
        ),
    ]
    for sensor_id, friendly_name, icon in default_sensors:
        state.set(
            sensor_id,
            int(0),
            {
                "unit_of_measurement": "aircraft",
                "friendly_name": friendly_name,
                "icon": icon,
                "state_class": "measurement",
            },
        )


def set_error_sensors():
    error_sensors = [
        ("sensor.aircraft_count", "Ilość wszystkich samolotów", "mdi:airplane"),
        (
            "sensor.aircraft_with_position_count",
            "Ilość samolotów ze znaną pozycją",
            "mdi:map-marker",
        ),
        (
            "sensor.aircraft_with_mlat_position_count",
            "Ilość samolotów z pozycją z mlat",
            "mdi:radar",
        ),
    ]
    for sensor_id, friendly_name, icon in error_sensors:
        state.set(
            sensor_id,
            int(-1),
            {
                "unit_of_measurement": "aircraft",
                "friendly_name": friendly_name,
                "icon": icon,
                "state_class": "measurement",
            },
        )


@service
@time_trigger("cron(*/10 * * * *)")
async def update_aircraft_count():
    url = "http://piaware/skyaware/data/aircraft.json"
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url, timeout=5) as response:
                if response.status == 200:
                    aircraft_data = response.json()
                    aircraft_list = aircraft_data.get("aircraft", [])
                    aircraft_count = len(aircraft_list)
                    with_position_count = 0
                    mlat_position_count = 0
                    for a in aircraft_list:
                        if all(
                            [key in a and a[key] is not None for key in ["lat", "lon"]]
                        ):
                            with_position_count += 1
                        if isinstance(a.get("mlat"), list) and len(a.get("mlat")) > 0:
                            mlat_position_count += 1
                    sensors_data = [
                        (
                            "sensor.aircraft_count",
                            aircraft_count,
                            "Ilość wszystkich samolotów",
                            "mdi:airplane",
                        ),
                        (
                            "sensor.aircraft_with_position_count",
                            with_position_count,
                            "Ilość samolotów ze znaną pozycją",
                            "mdi:map-marker",
                        ),
                        (
                            "sensor.aircraft_with_mlat_position_count",
                            mlat_position_count,
                            "Ilość samolotów z pozycją z mlat",
                            "mdi:radar",
                        ),
                    ]
                    for sensor_id, value, friendly_name, icon in sensors_data:
                        state.set(
                            sensor_id,
                            int(value),
                            {
                                "unit_of_measurement": "aircraft",
                                "friendly_name": friendly_name,
                                "icon": icon,
                                "state_class": "measurement",
                            },
                        )
                else:
                    set_default_sensors()
    except Exception as e:
        log.error(f"Error in update_aircraft_count: {str(e)}")
        set_error_sensors()
1 Like

This looks really interesting. I did try to implement on my HA, but I am lost on where to put the pyscript functions? Do I need to make my own custom component folder and throw it in there? What should the filename be?

Thanks for any help.

https://hacs-pyscript.readthedocs.io/en/stable/
You need to install custom_component pyscript and put my script into pyscript folder (name of script doesn’t matter, cron is defined as function decorator):