Skip to content

Commit bb072fd

Browse files
committed
AirSend duo
1 parent 1513a86 commit bb072fd

File tree

7 files changed

+325
-312
lines changed

7 files changed

+325
-312
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
# AirSend Home Assistant
44

5-
Component for sending radio commands (433-434Mhz) through the AirSend device.
5+
Component for sending radio commands through the AirSend (RF433) or AirSend duo (RF433 & RF868).
66

77
## Installation
88

9-
1. Add `airsend:` to your HA configuration (see configuration below).
10-
2. Into the terminal, run `wget -q -O - https://raw.githubusercontent.com/devmel/hass_airsend/master/install | bash -`
9+
1. Into the terminal, run `wget -q -O - https://raw.githubusercontent.com/devmel/hass_airsend/master/install | bash -`
1110
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).
12-
3. To allow a local LAN connection please install and start [hass_airsend-addon](https://github.com/devmel/hass_airsend-addon).
13-
4. Restart Home Assistant
11+
2. To allow a local LAN connection please install and start [hass_airsend-addon](https://github.com/devmel/hass_airsend-addon).
12+
3. Restart Home Assistant
13+
4. Add `airsend:` to your HA configuration (see configuration below).
14+
5. Restart Home Assistant
1415

1516
## Configuration
1617

custom_components/airsend/__init__.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,33 @@
22
from homeassistant.core import HomeAssistant
33
from homeassistant.helpers.typing import ConfigType
44
from homeassistant.helpers import discovery
5-
from homeassistant.const import (
6-
CONF_DEVICES,
5+
from homeassistant.components.hassio import (
6+
async_get_addon_info,
77
)
8+
from homeassistant.const import CONF_INTERNAL_URL
89

910
DOMAIN = "airsend"
10-
AS_TYPE = ['switch', 'cover', 'button']
11+
AS_TYPE = ["switch", "cover", "button"]
1112

12-
async def async_setup(hass : HomeAssistant, config : ConfigType):
13+
14+
async def async_setup(hass: HomeAssistant, config: ConfigType):
1315
"""Set up the AirSend component."""
1416
if DOMAIN not in config:
1517
return True
18+
internalurl = ""
19+
try:
20+
internalurl = config[DOMAIN][CONF_INTERNAL_URL]
21+
except KeyError:
22+
pass
23+
if internalurl == "":
24+
try:
25+
addon_info: dict = await async_get_addon_info(hass, "local_airsend")
26+
ip = addon_info["ip_address"]
27+
if ip:
28+
internalurl = "http://" + str(ip) + ":33863/"
29+
except KeyError:
30+
pass
31+
config[DOMAIN][CONF_INTERNAL_URL] = internalurl
1632
for plateform in AS_TYPE:
17-
discovery.load_platform(hass, plateform, DOMAIN, config[DOMAIN][CONF_DEVICES].copy(), config)
33+
discovery.load_platform(hass, plateform, DOMAIN, config[DOMAIN].copy(), config)
1834
return True
Lines changed: 31 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,44 @@
11
"""AirSend buttons."""
2-
import logging
3-
import json
42
from typing import Any
5-
from requests import get, post
3+
4+
from .device import Device
5+
6+
from homeassistant.components.button import ButtonEntity
67
from homeassistant.core import HomeAssistant
78
from homeassistant.helpers.typing import ConfigType
8-
from homeassistant.helpers.entity import async_generate_entity_id
9-
from homeassistant.components.hassio import (
10-
async_get_addon_discovery_info,
11-
async_get_addon_info,
12-
)
13-
from homeassistant.components.button import (
14-
ButtonEntity,
15-
)
16-
from . import (
17-
DOMAIN,
18-
)
19-
20-
_LOGGER = logging.getLogger(DOMAIN)
21-
22-
async def async_setup_platform(hass : HomeAssistant, config : ConfigType, async_add_entities, discovery_info=None):
23-
addons_url = ""
24-
try:
25-
addon_info: dict = await async_get_addon_info(hass, 'local_airsend')
26-
ip = addon_info["ip_address"]
27-
if ip:
28-
addons_url = "http://"+str(ip)+":33863/"
29-
# _LOGGER.warning("Addon '%s'", addon_info)
30-
except:
31-
pass
9+
10+
from homeassistant.const import CONF_DEVICES, CONF_INTERNAL_URL
11+
12+
from . import DOMAIN
13+
14+
15+
async def async_setup_platform(
16+
hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None
17+
) -> None:
3218
if discovery_info is None:
3319
return
34-
for name, options in discovery_info.items():
35-
if options['type'] == 4096 :
36-
id = ""
37-
apiKey = ""
38-
spurl = ""
39-
channel = {}
40-
note = {"method":1,"type":0,"value": "TOGGLE"}
41-
try:
42-
id = options['id']
43-
except KeyError:
44-
pass
45-
try:
46-
apiKey = options['apiKey']
47-
except KeyError:
48-
pass
49-
try:
50-
spurl = options['spurl']
51-
except KeyError:
52-
pass
53-
try:
54-
channel = options['channel']
55-
except KeyError:
56-
pass
57-
try:
58-
note = options['note']
59-
except KeyError:
60-
pass
61-
entity = AirSendButton(hass, name, id, options['type'], apiKey, addons_url, spurl, channel, note)
20+
for name, options in discovery_info[CONF_DEVICES].items():
21+
device = Device(name, options, discovery_info[CONF_INTERNAL_URL])
22+
if device.is_button:
23+
entity = AirSendButton(
24+
hass,
25+
device,
26+
)
6227
async_add_entities([entity])
63-
return
6428

6529

6630
class AirSendButton(ButtonEntity):
6731
"""Representation of an AirSend Button."""
6832

69-
def __init__(self, hass : HomeAssistant, name : str, id: str, type : int, apikey : str, addons_url : str, spurl : str, channel : dict, note : dict):
33+
def __init__(
34+
self,
35+
hass: HomeAssistant,
36+
device: Device,
37+
) -> None:
7038
"""Initialize a button."""
71-
self._name = name
72-
self._id = id
73-
self._type = type
74-
self._apikey = apikey
75-
self._addons_url = addons_url
76-
self._spurl = spurl
77-
self._channel = channel
78-
self._note = note
79-
uname = DOMAIN+name
39+
self._device = device
40+
uname = DOMAIN + device.name
8041
self._unique_id = "_".join(x for x in uname)
81-
self._state = False
8242

8343
@property
8444
def unique_id(self):
@@ -97,7 +57,7 @@ def should_poll(self):
9757
@property
9858
def name(self):
9959
"""Return the name of the device if any."""
100-
return self._name
60+
return self._device.name
10161

10262
@property
10363
def extra_state_attributes(self):
@@ -109,37 +69,8 @@ def assumed_state(self):
10969
"""Return true if unable to access real state of entity."""
11070
return True
11171

112-
def press(self) -> None:
72+
def press(self, **kwargs: Any) -> None:
11373
"""Handle the button press."""
114-
command = "6"
115-
note = self._note
116-
url = "https://airsend.cloud/device/" + str(self._id) + "/command/" + command + "/"
117-
payload = '{"wait": true, "channel":' + json.dumps(self._channel) + ', "thingnotes":{"notes":[' + json.dumps(
118-
note) + ']}}'
119-
self._action(url, payload, True)
120-
121-
def _action(self, cloud_url : str, payload : str, new_state : bool):
122-
status_code = 404
123-
if self._addons_url and self._spurl:
124-
headers = {"Authorization": "Bearer "+self._spurl, "content-type": "application/json", "User-Agent": "hass_airsend"}
125-
try:
126-
response = post(self._addons_url+"airsend/transfer", headers=headers, data=payload, timeout=6)
127-
status_code = 500
128-
jdata = json.loads(response.text)
129-
if jdata["type"] < 0x100:
130-
status_code = response.status_code
131-
except:
132-
pass
133-
if status_code != 200 and self._apikey and cloud_url:
134-
headers = {"Authorization": "Bearer "+self._apikey, "content-type": "application/json", "User-Agent": "hass_airsend"}
135-
try:
136-
response = get(cloud_url, headers=headers, timeout=10)
137-
status_code = response.status_code
138-
except:
139-
pass
140-
if status_code == 200:
141-
self._state = new_state
74+
note = {"method": 1, "type": 0, "value": "TOGGLE"}
75+
if self._device.transfer(note):
14276
self.schedule_update_ha_state()
143-
else:
144-
_LOGGER.error("action error : "+str(status_code))
145-
raise Exception("action error : "+str(status_code))

0 commit comments

Comments
 (0)