Skip to content

Commit

Permalink
async states
Browse files Browse the repository at this point in the history
  • Loading branch information
jouralexandre committed Aug 4, 2023
1 parent bb072fd commit 055cf05
Show file tree
Hide file tree
Showing 7 changed files with 51 additions and 35 deletions.
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,18 @@ Component for sending radio commands through the AirSend (RF433) or AirSend duo

## Installation

1. Into the terminal, run `wget -q -O - https://raw.githubusercontent.com/devmel/hass_airsend/master/install | bash -`
1. Install and start [hass_airsend-addon](https://github.com/devmel/hass_airsend-addon).
2. Go to `airsend.cloud -> import/export -> Export YAML` and copy the airsend.yaml file to the folder `config`
2. Add `airsend: !include airsend.yaml` at the end of your `configuration.yaml` file
3. Into the terminal, run `wget -q -O - https://raw.githubusercontent.com/devmel/hass_airsend/master/install | bash -`
OR copy the `airsend` folder into your [custom_components folder](https://developers.home-assistant.io/docs/creating_integration_file_structure/#where-home-assistant-looks-for-integrations).
2. To allow a local LAN connection please install and start [hass_airsend-addon](https://github.com/devmel/hass_airsend-addon).
3. Restart Home Assistant
4. Add `airsend:` to your HA configuration (see configuration below).
5. Restart Home Assistant
4. Restart Home Assistant

## Configuration

### YAML

To integrate `airsend` into Home Assistant, go to `airsend.cloud -> import/export -> Export YAML` and add the contents of the downloaded file into your HA configuration `configuration.yaml`.

#### Local LAN connection
The configuration allows to use the local mode (if [hass_airsend-addon](https://github.com/devmel/hass_airsend-addon) is started) by adding the field `spurl: !secret spurl` in each device. In this mode you must modify the file `secrets.yaml` by adding the local url of the AirSend with its local ipv4 (ex: 192.168.x.x so `spurl: sp://[email protected]`), the local ipv6 `fe80::` does not work because of virtualization. You can also remove fields `apiKey`.
The configuration allows to use the local mode by adding the field `spurl: !secret spurl` in each device. In this mode you must modify the file `secrets.yaml` by adding the local url of the AirSend with its local ipv4 (ex: 192.168.x.x so `spurl: sp://[email protected]`), the local ipv6 `fe80::` does not work because of virtualization. You can also remove fields `apiKey`.
The local mode requires the execution of [hass_airsend-addon](https://github.com/devmel/hass_airsend-addon), if it is not on the same machine it is possible to add the field `internal_url: http://x.x.x.x:33863/` in airsend.conf

## Preview

Expand Down
17 changes: 10 additions & 7 deletions custom_components/airsend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers import discovery
from homeassistant.components.hassio import (
async_get_addon_info,
get_addons_info,
)
from homeassistant.const import CONF_INTERNAL_URL

DOMAIN = "airsend"
AS_TYPE = ["switch", "cover", "button"]


async def async_setup(hass: HomeAssistant, config: ConfigType):
"""Set up the AirSend component."""
if DOMAIN not in config:
Expand All @@ -22,12 +21,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType):
pass
if internalurl == "":
try:
addon_info: dict = await async_get_addon_info(hass, "local_airsend")
ip = addon_info["ip_address"]
if ip:
internalurl = "http://" + str(ip) + ":33863/"
except KeyError:
addons_info = get_addons_info(hass)
for name, options in addons_info.items():
if "_airsend" in name:
ip = options["ip_address"]
if ip:
internalurl = "http://" + str(ip) + ":33863/"
except:
pass
if internalurl != "" and not internalurl.endswith('/'):
internalurl += "/"
config[DOMAIN][CONF_INTERNAL_URL] = internalurl
for plateform in AS_TYPE:
discovery.load_platform(hass, plateform, DOMAIN, config[DOMAIN].copy(), config)
Expand Down
2 changes: 1 addition & 1 deletion custom_components/airsend/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,5 @@ def assumed_state(self):
def press(self, **kwargs: Any) -> None:
"""Handle the button press."""
note = {"method": 1, "type": 0, "value": "TOGGLE"}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self.schedule_update_ha_state()
11 changes: 5 additions & 6 deletions custom_components/airsend/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from homeassistant.components.cover import CoverEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import ConfigType

from homeassistant.const import CONF_DEVICES, CONF_INTERNAL_URL

from . import DOMAIN
Expand Down Expand Up @@ -75,12 +74,12 @@ def assumed_state(self):
@property
def is_closed(self):
"""Return if the cover is closed."""
return not self._closed
return self._closed

def open_cover(self, **kwargs: Any) -> None:
"""Open the cover."""
note = {"method": 1, "type": 0, "value": "UP"}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self._closed = False
if self._device.is_cover_with_position:
self._attr_current_cover_position = 100
Expand All @@ -89,7 +88,7 @@ def open_cover(self, **kwargs: Any) -> None:
def close_cover(self, **kwargs: Any) -> None:
"""Close cover."""
note = {"method": 1, "type": 0, "value": "DOWN"}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self._closed = True
if self._device.is_cover_with_position:
self._attr_current_cover_position = 0
Expand All @@ -98,7 +97,7 @@ def close_cover(self, **kwargs: Any) -> None:
def stop_cover(self, **kwargs):
"""Stop the cover."""
note = {"method": 1, "type": 0, "value": "STOP"}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self._closed = False
if self._device.is_cover_with_position:
self._attr_current_cover_position = 50
Expand All @@ -108,7 +107,7 @@ def set_cover_position(self, **kwargs):
"""Move the cover to a specific position."""
position = int(kwargs["position"])
note = {"method": 1, "type": 9, "value": position}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self._attr_current_cover_position = position
self._closed = False
if self._attr_current_cover_position == 0:
Expand Down
33 changes: 25 additions & 8 deletions custom_components/airsend/device.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""AirSend device."""
import logging
import json
import hashlib
from requests import get, post, exceptions
from . import DOMAIN

Expand All @@ -23,6 +24,7 @@ def __init__(
self._rtype = None
self._apikey = None
self._spurl = None
self._wait = False
self._channel = {}
self._note = None
try:
Expand All @@ -41,6 +43,10 @@ def __init__(
self._spurl = options["spurl"]
except KeyError:
pass
try:
self._wait = eval(str(options["wait"]))
except KeyError:
pass
try:
self._channel = options["channel"]
except KeyError:
Expand Down Expand Up @@ -83,10 +89,15 @@ def is_switch(self) -> bool:
return True
return False

def transfer(self, note) -> bool:
def transfer(self, note, entity_id = None) -> bool:
"""Send a command."""
status_code = 404
if self._serviceurl and self._spurl:
ret = False
wait = 'false, "callback":"http://127.0.0.1/"'
if self._wait == True:
wait = 'true'
if self._serviceurl and self._spurl and entity_id is not None:
uid = hashlib.sha256(entity_id.encode('utf-8')).hexdigest()[:12]
jnote = json.dumps(note)
if (
self._note is not None
Expand All @@ -101,9 +112,9 @@ def transfer(self, note) -> bool:
):
jnote = json.dumps(self._note)
payload = (
'{"wait": true, "channel":'
'{"wait": '+wait+', "channel":'
+ json.dumps(self._channel)
+ ', "thingnotes":{"notes":['
+ ', "thingnotes":{"uid":"0x'+uid+'", "notes":['
+ jnote
+ "]}}"
)
Expand All @@ -119,9 +130,14 @@ def transfer(self, note) -> bool:
data=payload,
timeout=6,
)
status_code = 500
jdata = json.loads(response.text)
if jdata["type"] < 0x100:
if self._wait == True:
ret = True
status_code = 500
jdata = json.loads(response.text)
if jdata["type"] < 0x100:
status_code = response.status_code
else:
ret = None
status_code = response.status_code
except exceptions.RequestException:
pass
Expand Down Expand Up @@ -164,9 +180,10 @@ def transfer(self, note) -> bool:
try:
response = get(cloud_url, headers=headers, timeout=10)
status_code = response.status_code
ret = True
except exceptions.RequestException:
pass
if status_code == 200:
return True
return ret
_LOGGER.error("Transfer error '%s' : '%s'", self.name, status_code)
raise Exception("Transfer error " + self.name + " : " + str(status_code))
4 changes: 2 additions & 2 deletions custom_components/airsend/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ def is_on(self):
def turn_on(self, **kwargs: Any) -> None:
"""Turn the device on."""
note = {"method": 1, "type": 0, "value": "ON"}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self._state = True
self.schedule_update_ha_state()

def turn_off(self, **kwargs: Any) -> None:
"""Turn the device off."""
note = {"method": 1, "type": 0, "value": "OFF"}
if self._device.transfer(note):
if self._device.transfer(note, self.entity_id) == True:
self._state = False
self.schedule_update_ha_state()
2 changes: 1 addition & 1 deletion install
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ if [ -n "$haPath" ]; then
cd "$haPath/custom_components" || error "Could not change path to $haPath/custom_components"

info "Downloading AirSend Home Assistant Component"
wget "https://github.com/devmel/hass_airsend/releases/download/1.0/hass_airsend.zip"
wget "https://github.com/devmel/hass_airsend/releases/download/latest/hass_airsend.zip"

if [ -d "$haPath/custom_components/hass_airsend" ]; then
warn "airsend directory already exist, cleaning up..."
Expand Down

0 comments on commit 055cf05

Please sign in to comment.