Skip to content

Commit

Permalink
Fix for usage outside of HA OS (#16)
Browse files Browse the repository at this point in the history
- fixes for usage outside of HA OS
- add service dependency, add meaningful logs
  • Loading branch information
tlskinneriv authored Jul 20, 2024
1 parent 85b9ccb commit 7f91fb3
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 24 deletions.
13 changes: 13 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Monitor AWNET Logs",
"type": "shell",
"command": "while true; do docker logs -f addon_local_awnet_to_hass; sleep 1; done",
"group": {
"kind": "test",
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
}
]
}
15 changes: 15 additions & 0 deletions awnet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

All notable changes to this project will be documented in this file.

## [1.1.2] - 2024-07-20

### Added

- Meaningful log messages for when HA is unavailable or the Ambient Weather Station - Local integration is not set up.

### Changed

- HOUSEKEEPING: Updated base container to python3.12/alpine3.20.

### Fixed

- Update script to enable usage outside of HA OS. Closes [#15](https://github.com/tlskinneriv/hassio-addons/issues/15).
- Allow capital characters in MAC address override.

## [1.1.1] - 2024-03-30

### Changed
Expand Down
35 changes: 35 additions & 0 deletions awnet/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,38 @@ _These instructions are adapted from the Android app, but should be similar on o
- Upload Interval: (user determined, how often to send data to Home Assistant)
- Click "Save" at the bottom of the form
- Use the "Finish" button in the upper right to complete configuration

## Non-HA OS Options

The following options have been minimally tested, but should work properly. By default, the container/script
will listen on all IP addresses on port 7080.

### Container Setup without HA OS (e.g. HA Docker)

Obtain the container from the GitHub registry for your platform:

- armhf: ghcr.io/tlskinneriv/armhf-addon-awnet_to_hass
- armv7: ghcr.io/tlskinneriv/armv7-addon-awnet_to_hass
- aarch64: ghcr.io/tlskinneriv/aarch64-addon-awnet_to_hass
- amd64: ghcr.io/tlskinneriv/amd64-addon-awnet_to_hass
- i386: ghcr.io/tlskinneriv/i386-addon-awnet_to_hass

Run the container with at least the following environment variables set:

- HA_API_BASE_URL: The base URL to your HA instance's API; e.g. http://homeassistant.local:8123/api/
- HA_API_AUTH_TOKEN: A long-lived access token for HA. Create one under user profile -> security.

See the header comments in the [awnet.py][awnet.py] script for additional details and settings.

### Script Setup for use with HA Core

Obtain the [awnet.py][awnet.py] script.

Run the script with at least the following environment variables set:

- HA_API_BASE_URL: The base URL to your HA instance's API; e.g. http://homeassistant.local:8123/api/
- HA_API_AUTH_TOKEN: A long-lived access token for HA. Create one under user profile -> security.

See the header comments in the [awnet.py][awnet.py] script for additional details and settings.

[awnet.py]: https://github.com/tlskinneriv/hassio-addons/blob/master/awnet/rootfs/awnet.py
6 changes: 5 additions & 1 deletion awnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ This add-on and integration combo are a work in progress. Any feedback and/or co
[amd64-shield]: https://img.shields.io/badge/amd64-yes-green.svg
[armhf-shield]: https://img.shields.io/badge/armhf-yes-green.svg
[armv7-shield]: https://img.shields.io/badge/armv7-yes-green.svg
[i386-shield]: https://img.shields.io/badge/i386-yes-green.svg
[i386-shield]: https://img.shields.io/badge/i386-yes-green.svg

## Usage Without Home Assistant OS

See the [documentation](https://github.com/tlskinneriv/hassio-addons/blob/master/awnet/DOCS.md#non-ha-os-options) about usage of the container and script within in the event you are running HA in Docker or HA Core.
10 changes: 5 additions & 5 deletions awnet/build.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# https://developers.home-assistant.io/docs/add-ons/configuration#add-on-dockerfile
build_from:
aarch64: "ghcr.io/home-assistant/aarch64-base-python:3.11-alpine3.18"
amd64: "ghcr.io/home-assistant/amd64-base-python:3.11-alpine3.18"
armhf: "ghcr.io/home-assistant/armhf-base-python:3.11-alpine3.18"
armv7: "ghcr.io/home-assistant/armv7-base-python:3.11-alpine3.18"
i386: "ghcr.io/home-assistant/i386-base-python:3.11-alpine3.18"
aarch64: "ghcr.io/home-assistant/aarch64-base-python:3.12-alpine3.20"
amd64: "ghcr.io/home-assistant/amd64-base-python:3.12-alpine3.20"
armhf: "ghcr.io/home-assistant/armhf-base-python:3.12-alpine3.20"
armv7: "ghcr.io/home-assistant/armv7-base-python:3.12-alpine3.20"
i386: "ghcr.io/home-assistant/i386-base-python:3.12-alpine3.20"
labels:
org.opencontainers.image.title: "Home Assistant Add-on: AWNET to HASS"
org.opencontainers.image.description: "Addon to capture local Ambient Weather data in Home Assistant"
Expand Down
6 changes: 3 additions & 3 deletions awnet/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: AWNET to HASS
version: 1.1.1
version: 1.1.2
slug: awnet_to_hass
description: Addon to capture local Ambient Weather data in Home Assistant
arch:
Expand All @@ -13,8 +13,8 @@ options:
log_level: WARNING
schema:
log_level: list(DEBUG|INFO|WARNING|ERROR)
passkey_override: "match(^(?:[a-f0-9]{2}[\\.\\-:]?){5}[a-f0-9]{2}$)?"
passkey_override: "match(^(?:[a-fA-F0-9]{2}[\\.\\-:]?){5}[a-fA-F0-9]{2}$)?"
ports:
80/tcp: 7080
7080/tcp: 7080
init: false
image: "ghcr.io/tlskinneriv/{arch}-addon-awnet_to_hass"
60 changes: 48 additions & 12 deletions awnet/rootfs/awnet.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,22 @@
# original author: Austin of austinsnerdythings.com
# publish date: 2021-03-20

from urllib.parse import parse_qs
# In the event this script is to be used outside of this container configuration, the following
# environment variables must be set for proper operation:
#
# HA_API_BASE_URL: The base URL to your HA instance's API; e.g. http://homeassistant.local:8123/api/
# HA_API_AUTH_TOKEN: A long-lived access token for HA. Create one under user profile -> security.
#
# Optional variables:
#
# HTTP_LISTEN_HOST: Default: "" (all IP addresses); the host that this script will listen on for updates from the AWNET device
# HTTP_LISTEN_PORT: Default: 7080; The port that this script should listen on for updates from the AWNET device
# HA_API_VALIDATE_CERTIFICATE: Default: True; if set to True, verifies the SSL certificate on HTTPS requests
# LOG_LEVEL: Default: WARNING; log level setting; one of: DEBUG, INFO, WARNING, ERROR, CRITICAL
# PASSKEY_OVERRIDE: Default: ""; In the event that the PASSKEY value for the device is not a MAC address, use this field to
# statically set it to your devices MAC address.

from urllib.parse import parse_qs, urljoin
from wsgiref.headers import Headers
from wsgiref.simple_server import WSGIRequestHandler
import re
Expand All @@ -16,13 +31,19 @@
import logging
import sys

# set vars
AUTH_TOKEN = os.getenv("SUPERVISOR_TOKEN", "test")

ATTR_PASSKEY = 'PASSKEY'

_LOGGER = logging.getLogger(__name__)

# set vars
PASSKEY_OVERRIDE = os.environ.get("PASSKEY_OVERRIDE", "")
LOG_LEVEL = os.getenv("LOG_LEVEL", "WARNING")
HTTP_LISTEN_HOST = os.getenv("HTTP_LISTEN_HOST", "")
HTTP_LISTEN_PORT = int(os.getenv("HTTP_LISTEN_PORT", "7080"))
HA_API_AUTH_TOKEN = os.getenv("HA_API_AUTH_TOKEN", "test")
HA_API_BASE_URL = os.getenv("HA_API_BASE_URL", "http://supervisor/core/api/")
HA_API_VALIDATE_CERTIFICATE = os.getenv("HA_API_VALIDATE_CERTIFICATE", "True").lower() == 'true'

def get_headers(environ):
"""
Handles getting the headers from the environment, Content-Type is the special one
Expand All @@ -40,19 +61,26 @@ def publish(payload):
payload_json = json.dumps(payload)

head = {
"Authorization": "Bearer " + AUTH_TOKEN,
"Authorization": "Bearer " + HA_API_AUTH_TOKEN,
"content-type": "application/json",
}
good_responses = [200, 201]

url = "http://supervisor/core/api/services/awnet_local/update"
url = urljoin(HA_API_BASE_URL, "services/awnet_local/update")

response = requests.post(url, data=payload_json, headers=head)
response = requests.post(url, data=payload_json, headers=head, verify=HA_API_VALIDATE_CERTIFICATE)

if response.status_code in good_responses:
_LOGGER.info(f"Sent {payload_json}")
else:
_LOGGER.error(f"Failed to send {payload_json} to {url} with headers {head}; {response.content}")
_LOGGER.error(f"Failed to send data to Home Assistant. HTTP error code: {response.status_code}.")
_LOGGER.info(f"Failed payload: {payload_json} to {url} with headers {head}; {response.content}")
if response.status_code == 400:
_LOGGER.warning("'Ambient Weather Station - Local' may not be set up. Please install it from HACS and set it up with your device's MAC address.")
elif response.status_code == 502:
_LOGGER.warning("Home Assistant may not be available to receive requests.")
else:
_LOGGER.warning("An unknown error occurred.")


def handle_results(result):
Expand All @@ -66,7 +94,7 @@ def handle_results(result):
result[key] = result[key][0]
else:
_LOGGER.error('Unexpected list size for key %s', key)
m = re.search(pattern=r'(?:[a-f0-9]{2}[\.\-:]?){5}[a-f0-9]{2}', string=os.environ.get('PASSKEY_OVERRIDE', ''), flags=re.IGNORECASE)
m = re.search(pattern=r'(?:[a-f0-9]{2}[\.\-:]?){5}[a-f0-9]{2}', string=PASSKEY_OVERRIDE, flags=re.IGNORECASE)
if m is not None:
_LOGGER.debug('%s override: %s', ATTR_PASSKEY, m[0])
result[ATTR_PASSKEY] = m[0]
Expand Down Expand Up @@ -151,10 +179,18 @@ def log_message(self, format, *args):

logging.basicConfig(stream = sys.stdout,
format = '[%(asctime)s] [%(levelname)-8s] %(message)s (%(filename)s:%(lineno)d)',
level = sys.argv[1])
level = LOG_LEVEL)

# log variable values for DEBUG
_LOGGER.info("LOG_LEVEL: %s", LOG_LEVEL)
_LOGGER.info("HTTP_LISTEN_HOST: %s", HTTP_LISTEN_HOST)
_LOGGER.info("HTTP_LISTEN_PORT: %s", HTTP_LISTEN_PORT)
_LOGGER.info("HA_API_AUTH_TOKEN: %s", HA_API_AUTH_TOKEN)
_LOGGER.info("HA_API_BASE_URL: %s", HA_API_BASE_URL)
_LOGGER.info("HA_API_VALIDATE_CERTIFICATE: %s", HA_API_VALIDATE_CERTIFICATE)

# probably shouldn't run on port 80 but that's what I specified in the ambient weather console
httpd = make_server("", 80, application, handler_class=AWNETWSGIRequestHandler)
_LOGGER.info("Serving on http://localhost:80")
httpd = make_server(HTTP_LISTEN_HOST, HTTP_LISTEN_PORT, application, handler_class=AWNETWSGIRequestHandler)
_LOGGER.info(f"Serving on http://{HTTP_LISTEN_HOST}:{HTTP_LISTEN_PORT}")

httpd.serve_forever()
7 changes: 4 additions & 3 deletions awnet/rootfs/run.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/with-contenv bashio

export PASSKEY_OVERRIDE=$(bashio::config 'passkey_override')
export PASSKEY_OVERRIDE=${PASSKEY_OVEFRRRIDE:-$(bashio::config 'passkey_override')}
export LOG_LEVEL=${LOG_LEVEL:-$(bashio::config 'log_level')}
export HA_API_AUTH_TOKEN=${HA_API_AUTH_TOKEN:-$SUPERVISOR_TOKEN}

LOG_LEVEL=$(bashio::config 'log_level')
python3 awnet.py $LOG_LEVEL
python3 awnet.py

0 comments on commit 7f91fb3

Please sign in to comment.