├── blebox_switchbox.png
├── blebox_wlightbox1.png
├── blebox_wlightbox2.png
├── README.md
├── .gitignore
├── switch
└── blebox_switchbox.py
└── light
└── blebox_wlightbox.py
/blebox_switchbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zen/hass_blebox/master/blebox_switchbox.png
--------------------------------------------------------------------------------
/blebox_wlightbox1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zen/hass_blebox/master/blebox_wlightbox1.png
--------------------------------------------------------------------------------
/blebox_wlightbox2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zen/hass_blebox/master/blebox_wlightbox2.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Home Assistant Custom Components
2 |
3 | ## How to load custom components
4 | https://developers.home-assistant.io/docs/en/creating_component_loading.html
5 |
6 | ## Blebox switchBox(D)
7 | __To enable this switch, add the following lines to your configuration.yaml file:__
8 | ```
9 | switch:
10 | - platform: blebox_switchbox
11 | host: IP_ADDRESS
12 | ```
13 | __Configuration variables:__
14 | * __host__ (*Required*): The IP address of your switchBox(D), eg. 192.168.1.32
15 | * __name__ (*Optional*): The name to use when displaying this switch. If not set, will be used relay name from the device
16 | * __relay__ (*Optional*): The number of the relay. Default is 0, for switchBoxD you can set 0 or 1
17 |
18 |
19 |
20 | ## Blebox wLightBox
21 | __To enable this switch, add the following lines to your configuration.yaml file:__
22 | ```
23 | light:
24 | - platform: blebox_wlightbox
25 | host: IP_ADDRESS
26 | ```
27 | __Configuration variables:__
28 | * __host__ (*Required*): The IP address of your wLightBox, eg. 192.168.1.32
29 | * __name__ (*Optional*): The name to use when displaying this switch. If not set, will be used the device name
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | *.egg-info/
24 | .installed.cfg
25 | *.egg
26 | MANIFEST
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 | .pytest_cache/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 | db.sqlite3
58 |
59 | # Flask stuff:
60 | instance/
61 | .webassets-cache
62 |
63 | # Scrapy stuff:
64 | .scrapy
65 |
66 | # Sphinx documentation
67 | docs/_build/
68 |
69 | # PyBuilder
70 | target/
71 |
72 | # Jupyter Notebook
73 | .ipynb_checkpoints
74 |
75 | # pyenv
76 | .python-version
77 |
78 | # celery beat schedule file
79 | celerybeat-schedule
80 |
81 | # SageMath parsed files
82 | *.sage.py
83 |
84 | # Environments
85 | .env
86 | .venv
87 | env/
88 | venv/
89 | ENV/
90 | env.bak/
91 | venv.bak/
92 |
93 | # Spyder project settings
94 | .spyderproject
95 | .spyproject
96 |
97 | # Rope project settings
98 | .ropeproject
99 |
100 | # mkdocs documentation
101 | /site
102 |
103 | # mypy
104 | .mypy_cache/
105 |
--------------------------------------------------------------------------------
/switch/blebox_switchbox.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import voluptuous as vol
3 | import json
4 | import asyncio
5 | import async_timeout
6 |
7 | from homeassistant.components.switch import (SwitchDevice, PLATFORM_SCHEMA)
8 | from homeassistant.const import (CONF_NAME, CONF_HOST, CONF_TIMEOUT, STATE_OFF, STATE_ON)
9 | import homeassistant.helpers.config_validation as cv
10 | from homeassistant.helpers.aiohttp_client import async_get_clientsession
11 |
12 | LOGGING = logging.getLogger(__name__)
13 | CONF_RELAY = 'relay'
14 | DEFAULT_NAME = 'Blebox switchBox'
15 | DEFAULT_RELAY = 0
16 | DEFAULT_TIMEOUT = 10
17 |
18 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
19 | vol.Required(CONF_HOST): cv.string,
20 | vol.Optional(CONF_NAME): cv.string,
21 | vol.Optional(CONF_RELAY, default=DEFAULT_RELAY): cv.positive_int,
22 | vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
23 | })
24 |
25 | @asyncio.coroutine
26 | def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
27 | name = config.get(CONF_NAME)
28 | host = config.get(CONF_HOST)
29 | relay = config.get(CONF_RELAY)
30 | timeout = config.get(CONF_TIMEOUT)
31 |
32 | switch = BleboxSwitchBoxSwitch(name, host, relay, timeout)
33 | yield from switch.async_relay_init(hass)
34 | async_add_devices([switch])
35 |
36 | class BleboxSwitchBoxSwitch(SwitchDevice):
37 |
38 | def __init__(self, name, host, relay, timeout):
39 | self._name = name
40 | self._state = 0
41 | self._host = host
42 | self._relay = relay
43 | self._timeout = timeout
44 | self._available = False
45 |
46 | @property
47 | def available(self):
48 | return self._available
49 |
50 | @property
51 | def name(self):
52 | return self._name
53 |
54 | @property
55 | def state(self):
56 | return self._state
57 |
58 | @state.setter
59 | def state(self, state):
60 | self._state = STATE_ON if state else STATE_OFF
61 |
62 | @property
63 | def is_on(self):
64 | return self._state == STATE_ON
65 |
66 | @asyncio.coroutine
67 | def async_turn_on(self, **kwargs):
68 | yield from self.set_relay_state(1)
69 |
70 | @asyncio.coroutine
71 | def async_turn_off(self, **kwargs):
72 | yield from self.set_relay_state(0)
73 |
74 | @asyncio.coroutine
75 | def async_relay_init(self, hass):
76 | relay_info = yield from self.async_update_relay_info(hass)
77 |
78 | if not self._name:
79 | self._name = relay_info['name'] if relay_info else DEFAULT_NAME
80 |
81 | return relay_info
82 |
83 | @asyncio.coroutine
84 | def async_update_relay_info(self, hass):
85 | relay_info = yield from self.get_relay_info(hass)
86 |
87 | if relay_info:
88 | self.state = relay_info['state']
89 | self._available = True
90 | else:
91 | self.state = 0
92 | self._available = False
93 |
94 | return relay_info
95 |
96 | @asyncio.coroutine
97 | def async_update(self):
98 | yield from self.async_update_relay_info(self.hass)
99 |
100 | @asyncio.coroutine
101 | def set_relay_state(self, state):
102 | websession = async_get_clientsession(self.hass)
103 | resource = 'http://%s/api/relay/set' % self._host
104 | payload = '{"relays": [{"relay": %i, "state": %i}]}' % (self._relay, state)
105 |
106 | try:
107 | with async_timeout.timeout(self._timeout, loop=self.hass.loop):
108 | req = yield from getattr(websession, 'post')(resource, data=bytes(payload, 'utf-8'))
109 | text = yield from req.text()
110 | relay_info = json.loads(text)['relays'][self._relay]
111 | return relay_info
112 | except:
113 | return None
114 |
115 | @asyncio.coroutine
116 | def get_relay_info(self, hass):
117 | websession = async_get_clientsession(hass)
118 | resource = 'http://%s/api/relay/state' % self._host
119 |
120 | try:
121 | with async_timeout.timeout(self._timeout, loop=hass.loop):
122 | req = yield from websession.get(resource)
123 | text = yield from req.text()
124 | relay_info = json.loads(text)['relays'][self._relay]
125 | return relay_info
126 | except:
127 | return None
128 |
--------------------------------------------------------------------------------
/light/blebox_wlightbox.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import voluptuous as vol
3 | import json
4 | import asyncio
5 | import async_timeout
6 | import homeassistant.helpers.config_validation as cv
7 | from homeassistant.components.light import (
8 | ATTR_BRIGHTNESS, ATTR_EFFECT, ATTR_HS_COLOR,
9 | ATTR_WHITE_VALUE, SUPPORT_BRIGHTNESS, SUPPORT_EFFECT,
10 | SUPPORT_COLOR, SUPPORT_WHITE_VALUE, Light, PLATFORM_SCHEMA)
11 | from homeassistant.const import (CONF_NAME, CONF_HOST, CONF_TIMEOUT, STATE_OFF, STATE_ON)
12 | from homeassistant.helpers.aiohttp_client import async_get_clientsession
13 | from homeassistant.util.color import (color_hsb_to_RGB, color_hsv_to_RGB, color_RGB_to_hsv, rgb_hex_to_rgb_list)
14 |
15 | LOGGING = logging.getLogger(__name__)
16 | LIGHT_EFFECT_LIST = ['BRAK', 'ŚCIEMNIANIE', 'RGB', 'POLICJA', 'RELAKS', 'STROBOSKOP']
17 | SUPPORTED_FEATURES_MONO = (SUPPORT_BRIGHTNESS)
18 | SUPPORTED_FEATURES_RGB = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT | SUPPORT_COLOR)
19 | SUPPORTED_FEATURES_RGBW = (SUPPORT_BRIGHTNESS | SUPPORT_EFFECT | SUPPORT_COLOR | SUPPORT_WHITE_VALUE)
20 | DEFAULT_NAME = 'Blebox wLightBox'
21 | DEFAULT_RELAY = 0
22 | DEFAULT_TIMEOUT = 10
23 |
24 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
25 | vol.Required(CONF_HOST): cv.string,
26 | vol.Optional(CONF_NAME): cv.string,
27 | vol.Optional(CONF_TIMEOUT, default=DEFAULT_TIMEOUT): cv.positive_int,
28 | })
29 |
30 | @asyncio.coroutine
31 | def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
32 | name = config.get(CONF_NAME)
33 | host = config.get(CONF_HOST)
34 | timeout = config.get(CONF_TIMEOUT)
35 |
36 | light = BleboxWlightBoxLight(name, host, timeout)
37 | yield from light.async_device_init(hass)
38 | async_add_devices([light])
39 |
40 | class BleboxWlightBoxLight(Light):
41 | def __init__(self, name, host, timeout):
42 | self._name = name
43 | self._host = host
44 | self._timeout = timeout
45 | self._state = False
46 | self._hs_color = (0, 0)
47 | self._brightness = 255
48 | self._white = 0
49 | self._effect_list = LIGHT_EFFECT_LIST
50 | self._effect = 'BRAK'
51 | self._color_mode = 1
52 | self._available = False
53 |
54 | @property
55 | def should_poll(self):
56 | return True
57 |
58 | @property
59 | def name(self):
60 | return self._name
61 |
62 | @property
63 | def state(self):
64 | return self._state
65 |
66 | @state.setter
67 | def state(self, state):
68 | self._state = STATE_ON if state else STATE_OFF
69 |
70 | @property
71 | def is_on(self):
72 | return self._state == STATE_ON
73 |
74 | @property
75 | def available(self):
76 | return self._available
77 |
78 | @property
79 | def brightness(self):
80 | return self._brightness
81 |
82 | @property
83 | def hs_color(self):
84 | return self._hs_color
85 |
86 | @property
87 | def white_value(self):
88 | return self._white
89 |
90 | @property
91 | def effect_list(self):
92 | return self._effect_list
93 |
94 | @property
95 | def effect(self):
96 | return self._effect
97 |
98 | @property
99 | def supported_features(self):
100 | return SUPPORTED_FEATURES_RGBW if self._color_mode == 1 else (SUPPORTED_FEATURES_RGB if self._color_mode == 2 else SUPPORTED_FEATURES_MONO)
101 |
102 | @asyncio.coroutine
103 | def async_device_init(self, hass):
104 | device_info = yield from self.async_update_device_info(hass)
105 |
106 | if not self._name:
107 | self._name = device_info['device']['deviceName'] if device_info else DEFAULT_NAME
108 |
109 | return device_info
110 |
111 | @asyncio.coroutine
112 | def async_update_device_info(self, hass):
113 |
114 | device_info = None
115 |
116 | try:
117 | device_info = yield from self.get_device_info(hass)
118 | self._available = True
119 | self._color_mode = device_info['rgbw']['colorMode']
120 |
121 | current_color = device_info['rgbw']['desiredColor']
122 | effect_id = device_info['rgbw']['effectID']
123 | except:
124 | self._available = False
125 | current_color = '00000000'
126 | effect_id = 0
127 |
128 | if current_color != '00000000':
129 | self.state = True
130 |
131 | rgb = current_color[:6]
132 | rgb = rgb_hex_to_rgb_list(rgb)
133 | hsv = color_RGB_to_hsv(*tuple(rgb))
134 |
135 | self._brightness = int((hsv[2]*255)/100)
136 | self._white = int(current_color[6:8], 16)
137 | self._hs_color = hsv[0:2]
138 | self._effect = LIGHT_EFFECT_LIST[effect_id]
139 | else:
140 | self.state = False
141 |
142 | return device_info
143 |
144 | @asyncio.coroutine
145 | def async_update(self):
146 | yield from self.async_update_device_info(self.hass)
147 |
148 | @asyncio.coroutine
149 | def async_turn_on(self, **kwargs):
150 | if ATTR_HS_COLOR in kwargs:
151 | self._hs_color = kwargs[ATTR_HS_COLOR]
152 |
153 | if ATTR_BRIGHTNESS in kwargs:
154 | self._brightness = kwargs[ATTR_BRIGHTNESS]
155 |
156 | if ATTR_WHITE_VALUE in kwargs:
157 | self._white = kwargs[ATTR_WHITE_VALUE]
158 |
159 | if ATTR_EFFECT in kwargs:
160 | self._effect = kwargs[ATTR_EFFECT]
161 |
162 | if self._color_mode == 2: #RGB
163 | self._white = 0
164 | elif self._color_mode == 3: #MONO
165 | self._white = self._brightness
166 | self._hs_color = (0, 0)
167 |
168 | rgb = color_hsv_to_RGB(self._hs_color[0], self._hs_color[1], (self._brightness/255)*100)
169 | rgbw = '{0:02x}{1:02x}{2:02x}{3:02x}'.format(rgb[0], rgb[1], rgb[2], self._white)
170 |
171 | yield from self.set_device_color(rgbw, self._effect)
172 |
173 | @asyncio.coroutine
174 | def async_turn_off(self):
175 | yield from self.set_device_color('00000000')
176 |
177 | @asyncio.coroutine
178 | def set_device_color(self, color, effect = 'BRAK'):
179 | websession = async_get_clientsession(self.hass)
180 | resource = 'http://%s/api/rgbw/set' % self._host
181 | effect_id = LIGHT_EFFECT_LIST.index(effect)
182 | payload = '{"rgbw": {"desiredColor": "%s", "effectID": %i}}' % (color, effect_id)
183 |
184 | try:
185 | with async_timeout.timeout(self._timeout, loop=self.hass.loop):
186 | req = yield from getattr(websession, 'post')(resource, data=bytes(payload, 'utf-8'))
187 | text = yield from req.text()
188 | return json.loads(text)['rgbw']
189 | except:
190 | return None
191 |
192 | @asyncio.coroutine
193 | def get_device_info(self, hass):
194 | websession = async_get_clientsession(hass)
195 | resource = 'http://%s/api/device/state' % self._host
196 |
197 | try:
198 | with async_timeout.timeout(self._timeout, loop=hass.loop):
199 | req = yield from websession.get(resource)
200 | text = yield from req.text()
201 | device_info = json.loads(text)
202 | device = device_info['device']
203 | return device_info
204 | except:
205 | return None
206 |
--------------------------------------------------------------------------------