Skip to content

Instantly share code, notes, and snippets.

@ispiropoulos
Created August 28, 2018 09:16
Show Gist options
  • 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
@fernmac2
Copy link

fernmac2 commented May 13, 2019 via email

@eddsa
Copy link

eddsa commented May 13, 2019

Hi Everyome, So far I integrated the Shelly 1 as switch. Now I tried with the Shelly 2.5 and was unable to get it running. Has anyone integrated got this script running with a Shelly 2 or Shelly 2.5?

@Gorbac
Copy link

Gorbac commented May 17, 2019

Hi Everyome, So far I integrated the Shelly 1 as switch. Now I tried with the Shelly 2.5 and was unable to get it running. Has anyone integrated got this script running with a Shelly 2 or Shelly 2.5?

Yes. I run a lot of Shelly 1 and 2.5. For the shelly 2.5 use "path: /relay/0" and "path: /relay/1" for each switch.

Great component!

@eddsa
Copy link

eddsa commented May 21, 2019

Thanks @Gorbac

I try that and did not work. I my case the Shelly 2.5 is operated as roller shutter. Is this same on your end? Do you mind copying your relevant configuration for the Shelly 2.5? Thanks for your support.

Regards. Edip

@eddsa
Copy link

eddsa commented May 27, 2019

@Gorbac would really appreciate an answer.

@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