-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy path__init__.py
More file actions
171 lines (141 loc) · 6.47 KB
/
__init__.py
File metadata and controls
171 lines (141 loc) · 6.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import aiofiles
import aiohttp
import asyncio
import binascii
from packaging import version
import json
import logging
import os.path
import requests
import struct
import voluptuous as vol
from aiohttp import ClientSession
from homeassistant.const import (
ATTR_FRIENDLY_NAME, __version__ as current_ha_version)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
_LOGGER = logging.getLogger(__name__)
DOMAIN = 'smartir'
VERSION = '1.18.1'
MANIFEST_URL = (
"https://raw.githubusercontent.com/"
"smartHomeHub/SmartIR/{}/"
"custom_components/smartir/manifest.json")
REMOTE_BASE_URL = (
"https://raw.githubusercontent.com/"
"smartHomeHub/SmartIR/{}/"
"custom_components/smartir/")
COMPONENT_ABS_DIR = os.path.dirname(
os.path.abspath(__file__))
CONF_CHECK_UPDATES = 'check_updates'
CONF_UPDATE_BRANCH = 'update_branch'
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(CONF_CHECK_UPDATES, default=True): cv.boolean,
vol.Optional(CONF_UPDATE_BRANCH, default='master'): vol.In(
['master', 'rc'])
})
}, extra=vol.ALLOW_EXTRA)
async def async_setup(hass, config):
"""Set up the SmartIR component."""
conf = config.get(DOMAIN)
if conf is None:
return True
check_updates = conf[CONF_CHECK_UPDATES]
update_branch = conf[CONF_UPDATE_BRANCH]
async def _check_updates(service):
await _update(hass, update_branch)
async def _update_component(service):
await _update(hass, update_branch, True)
hass.services.async_register(DOMAIN, 'check_updates', _check_updates)
hass.services.async_register(DOMAIN, 'update_component', _update_component)
if check_updates:
await _update(hass, update_branch, False, False)
return True
async def _update(hass, branch, do_update=False, notify_if_latest=True):
try:
async with aiohttp.ClientSession() as session:
async with session.get(MANIFEST_URL.format(branch)) as response:
if response.status == 200:
data = await response.json(content_type='text/plain')
min_ha_version = data['homeassistant']
last_version = data['updater']['version']
release_notes = data['updater']['releaseNotes']
if version.parse(last_version) <= version.parse(VERSION):
if notify_if_latest:
hass.components.persistent_notification.async_create(
"You're already using the latest version!",
title='SmartIR')
return
if version.parse(current_ha_version) < version.parse(min_ha_version):
hass.components.persistent_notification.async_create(
"There is a new version of SmartIR integration, but it is **incompatible** "
"with your system. Please first update Home Assistant.", title='SmartIR')
return
if do_update is False:
hass.components.persistent_notification.async_create(
"A new version of SmartIR integration is available ({}). "
"Call the ``smartir.update_component`` service to update "
"the integration. \n\n **Release notes:** \n{}"
.format(last_version, release_notes), title='SmartIR')
return
# Begin update
files = data['updater']['files']
has_errors = False
for file in files:
try:
source = REMOTE_BASE_URL.format(branch) + file
dest = os.path.join(COMPONENT_ABS_DIR, file)
os.makedirs(os.path.dirname(dest), exist_ok=True)
await Helper.downloader(source, dest)
except Exception:
has_errors = True
_LOGGER.error("Error updating %s. Please update the file manually.", file)
if has_errors:
hass.components.persistent_notification.async_create(
"There was an error updating one or more files of SmartIR. "
"Please check the logs for more information.", title='SmartIR')
else:
hass.components.persistent_notification.async_create(
"Successfully updated to {}. Please restart Home Assistant."
.format(last_version), title='SmartIR')
except Exception:
_LOGGER.error("An error occurred while checking for updates.")
class Helper():
@staticmethod
async def downloader(source, dest):
async with aiohttp.ClientSession() as session:
async with session.get(source) as response:
if response.status == 200:
async with aiofiles.open(dest, mode='wb') as f:
await f.write(await response.read())
else:
raise Exception("File not found")
@staticmethod
def pronto2lirc(pronto):
codes = [int(binascii.hexlify(pronto[i:i+2]), 16) for i in range(0, len(pronto), 2)]
if codes[0]:
raise ValueError("Pronto code should start with 0000")
if len(codes) != 4 + 2 * (codes[2] + codes[3]):
raise ValueError("Number of pulse widths does not match the preamble")
frequency = 1 / (codes[1] * 0.241246)
return [int(round(code / frequency)) for code in codes[4:]]
@staticmethod
def lirc2broadlink(pulses):
array = bytearray()
for pulse in pulses:
pulse = int(pulse * 269 / 8192)
if pulse < 256:
array += bytearray(struct.pack('>B', pulse))
else:
array += bytearray([0x00])
array += bytearray(struct.pack('>H', pulse))
packet = bytearray([0x26, 0x00])
packet += bytearray(struct.pack('<H', len(array)))
packet += array
packet += bytearray([0x0d, 0x05])
# Add 0s to make ultimate packet size a multiple of 16 for 128-bit AES encryption.
remainder = (len(packet) + 4) % 16
if remainder:
packet += bytearray(16 - remainder)
return packet