Skip to content

Instantly share code, notes, and snippets.

@catchdave
Created July 7, 2019 00:29
Show Gist options
  • Save catchdave/a6dc17be9a4f55559d12c1a094573707 to your computer and use it in GitHub Desktop.
Save catchdave/a6dc17be9a4f55559d12c1a094573707 to your computer and use it in GitHub Desktop.
Home Assistant Python Script to generalize pico remotes for any non-lutron light
#
# Script to manage a light using standard controls from a Lutron Pico Remote
# This will translate the standard button meanings on a Pico to any light controlled
# by Home Assistant.
# The "favourite" button is presumed to be 50% brightness (but can be overriden).
# Expected data packet is: { new_state: X, entity_id: entity_id, fav_brightness: [0-100] }
# new_state: REQUIRED. The pico value that triggered the event.
# entity_id: REQUIRED. The entity_id of the light to control
# fav_brightness: OPTIONAL. What brightness percentage to set when the favourite button is pressed (int 1 - 100).
#
# Example call from automations.yaml:
# trigger:
# - platform: state
# entity_id: sensor.PICO_REMOTE_ID
# from: '0'
# action:
# - data_template:
# entity_id: light.LIGHT_TO_CONTROL_ID
# new_state: "{{ trigger.to_state.state }}"
# service: python_script.pico_light_switch_std
#
# Note: In order to work best with LIFX bulbs, pressing ON has two modes. If the bulb is not already on, then
# ON will turn on the light at the previously set brightness. However, if the light is already on, then
# ON will set brightness to maximum (255)
#
# Function Definitions
def get_fav_brightness(data):
try:
fav_percent = int(data.get('fav_brightness', 50))
return int(255 * fav_percent / 100)
except ValueError:
return 50
# Init
BUTTON_ON = 1
BUTTON_FAV = 2
BUTTON_OFF = 4
BUTTON_RAISE = 8
BUTTON_LOWER = 16
button_values = [BUTTON_ON, BUTTON_FAV, BUTTON_OFF, BUTTON_RAISE, BUTTON_LOWER]
BRIGHTNESS_STEP = 5 # Brightness value to step up/down
BRIGHTNESS_MAX = 255
entity_id = data.get('entity_id')
button = int(data.get('new_state'))
brightness = None
action = 'turn_on' # Most buttons require turning on
action_data = { "entity_id" : entity_id }
# Validation
valid = True
if entity_id is None:
logger.warning("No entity ID provided to pico_light_switch_std script")
valid = False
if button is None or button not in button_values:
logger.warning("Invalid or missing new_state value provided to pico_light_switch_std script")
valid = False
if valid:
try:
cur_entity_state = hass.states.get(entity_id)
cur_brightness = cur_entity_state.attributes['brightness']
except KeyError:
cur_brightness = 0
logger.debug("Payload received: {}".format(data))
logger.debug("Current brightness: {}".format(cur_brightness))
# Build Service Call Payload
if button == BUTTON_OFF:
action = 'turn_off'
elif button == BUTTON_RAISE:
brightness = cur_brightness + BRIGHTNESS_STEP
if brightness > 255: brightness = 255 # sigh: apparantly min/max fn's are not considered "safe"
elif button == BUTTON_LOWER:
brightness = cur_brightness - BRIGHTNESS_STEP
if brightness < 0: brightness = 0
elif button == BUTTON_FAV:
brightness = get_fav_brightness(data)
elif button == BUTTON_ON:
if cur_entity_state.state == 'on':
brightness = BRIGHTNESS_MAX
if brightness is not None:
action_data['brightness'] = brightness
# Make service call to light
logger.info("Making '%s' call with payload: %s", action, action_data)
hass.services.call('light', action, action_data)
@bigkraig
Copy link

FWIW you can also do something like this to allow you to do more customized on a button:

BUTTON_MAP = {                                                                                                                                                                           
  0: 'release',                                                                                                                                                                          
  1: 'on',                                                                                                                                                                               
  2: 'favorite',                                                                                                                                                                         
  4: 'off',                                                                                                                                                                              
  8: 'raise',                                                                                                                                                                            
  16: 'lower'                                                                                                                                                                            
  }                                                                                                                                                                                      
    logger.debug("Payload received: {}".format(data))                                                                                                                                    
    logger.debug("Current brightness: {}".format(cur_brightness))                                                                                                                        
                                                                                                                                                                                         
    if data.get('buttons') and data.get('buttons').get(BUTTON_MAP.get(button)):                                                                                                          
        d = data.get('buttons').get(BUTTON_MAP.get(button))[0] # Should iterate over each                                                                                                
        domain, action = d.get('service').split('.')                                                                                                                                     
        action_data = d.get('data')                                                                                                                                                      
                                                                                                                                                                                         
    else:                                                                                                                                                                                
        # Build Service Call Payload                                                                                                                                                     
        if button == BUTTON_OFF:                                                                                                                                                         
            action = 'turn_off'                                                                                                                                                          
...
- id: Kitchen Pico
  alias: Kitchen Pico
  hide_entity: True
  trigger:
  - platform: state
    entity_id: sensor.kitchen_pico
  action:
  - service: python_script.pico_light_switch_std
    data_template:
      new_state: '{{ trigger.to_state.state }}'
      entity_id: light.kitchen
      buttons:
        'on':
        - service: hue.hue_activate_scene
          data:
            group_name: Kitchen
            scene_name: Bright

@catchdave
Copy link
Author

Yeah, you can make any button do anything really. I had one set up to record different events to a spreadsheet (and heavy use of a label maker).
The issue really comes down to intuition and expectations of most humans using your switch. Unless you label each button, most people will assume the middle button will be midway brightness, the up increases brightness, etc. What devices "lend themselves" to is super important for good use.

@catchdave
Copy link
Author

By modifying the constants to the below, this will work with the built-in configuration:

BUTTON_ON    = 2
BUTTON_FAV   = 3
BUTTON_OFF   = 4
BUTTON_RAISE = 5
BUTTON_LOWER = 6

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