Skip to content

Instantly share code, notes, and snippets.

@ispiropoulos
Created August 28, 2018 09:16
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save ispiropoulos/90a5f215e71f4dde635e3e3407fb5804 to your computer and use it in GitHub Desktop.
Save ispiropoulos/90a5f215e71f4dde635e3e3407fb5804 to your computer and use it in GitHub Desktop.
Shelly Switch Home Assistant Component
"""
Support for The Shelly Wifi switch.
Save this file inside ".homeassistant/custom_components/switch" (create the folders if not present) and restart HASS.
usage example:
switch:
- platform: shelly
switches:
shelly_switch:
path: /relay/0 (optional, defaults to /relay/0)
host: 10.0.0.219
username: admin
password: admin
Path is optional and defaults to '/relay/0'. If you have the 2-relay Shelly for the second one use /relay/1.
Username & Password are optional. Use only if you have enabled authentication from the shelly web interface.
"""
import logging
import requests
import voluptuous as vol
from homeassistant.components.switch import SwitchDevice, PLATFORM_SCHEMA
from homeassistant.const import (
CONF_HOST, CONF_NAME, CONF_PATH, CONF_USERNAME, CONF_PASSWORD,
CONF_SWITCHES)
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEFAULT_PATH = "/relay/0"
SWITCH_SCHEMA = vol.Schema({
vol.Required(CONF_HOST): cv.string,
vol.Optional(CONF_NAME): cv.string,
vol.Optional(CONF_PATH, default=DEFAULT_PATH): cv.string,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
})
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_SWITCHES): vol.Schema({cv.slug: SWITCH_SCHEMA}),
})
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
"""Set up Shelly Wifi switches."""
switches = config.get('switches', {})
devices = []
for dev_name, properties in switches.items():
devices.append(
ShellySwitch(
hass,
properties.get(CONF_NAME, dev_name),
properties.get(CONF_HOST, None),
properties.get(CONF_PATH, DEFAULT_PATH),
properties.get(CONF_USERNAME, None),
properties.get(CONF_PASSWORD)))
add_devices_callback(devices)
class ShellySwitch(SwitchDevice):
"""Representation of a Shelly Wifi switch."""
def __init__(self, hass, name, host, path, user, passwd):
"""Initialize the device."""
self._hass = hass
self._name = name
self._state = False
self._url = 'http://{}{}'.format(host, path)
if user is not None:
self._auth = (user, passwd)
else:
self._auth = None
def _switch(self, newstate):
"""Switch on or off."""
_LOGGER.info("Switching to state: %s", newstate)
try:
req = requests.get('{}?turn={}'.format(self._url, newstate),
auth=self._auth, timeout=5)
result = req.json()['ison']
if newstate == 'on':
return result == True
else:
return result == False
except requests.RequestException as error:
_LOGGER.error("Switching failed: " + error)
def _query_state(self):
"""Query switch state."""
_LOGGER.info("Querying state from: %s", self._url)
try:
req = requests.get('{}'.format(self._url),
auth=self._auth, timeout=5)
return req.json()['ison'] == True
except requests.RequestException as error:
_LOGGER.error("State query failed: " + error)
@property
def should_poll(self):
"""Return the polling state."""
return True
@property
def name(self):
"""Return the name of the switch."""
return self._name
@property
def is_on(self):
"""Return true if device is on."""
return self._state
def update(self):
"""Update device state."""
self._state = self._query_state()
def turn_on(self, **kwargs):
"""Turn the device on."""
if self._switch('on'):
self._state = True
def turn_off(self, **kwargs):
"""Turn the device off."""
if self._switch('off'):
self._state = False
@Gorbac
Copy link

Gorbac commented May 27, 2019

Sorry, I use it as switch

@jonhgaspar
Copy link

have the error:

I have already created the files and continue with errors.

"Setup failed for switch: No setup function defined."

Someone help?

@genem2
Copy link

genem2 commented Aug 7, 2019

Also working great here, thank you for sharing this.
But I did notice this if you're interested: When shutting HomeAssistant (96.5), the log file receives:

2019-08-06 17:52:51 ERROR (MainThread) [homeassistant.core] Error doing job: Future exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)
TypeError: stop_shelly() takes 0 positional arguments but 1 was given

@mszpiler
Copy link

@fernmac2
There are some Change required, where the rest remains actually the same
**1) Cusomer Component Folder and File Name **
It was "homeassistant/custom_components/switch/shelly.py"
It need to be "homeassistant/custom_components/shelly/switch.py".
It is just a renaming

  1. With 0.92 and later you need also to add the following file, also linked above in the same Folder "homeassistant/custom_components/shelly/"
    2a) Add the file "manifest.json". Just create an empty file and copy the file into the Folder. My text is
    {
    "domain": "shelly",
    "name": "Shelly Cloud",
    "documentation": "https://gist.github.com/ispiropoulos/90a5f215e71f4dde635e3e3407fb5804",
    "dependencies": [],
    "codeowners": [],
    "requirements": []
    }

2b) ad an empty file named "init.py". There is really not text

So your custom folder and content should look like this:
image

Thank you - it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment