Python LimitlessLED via RF

Check-in [c50aa58a64]
Login
Overview
Comment:Added README with limited documentation
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: c50aa58a6427d86585ae3fcaad093656a1194bc42971609655decadf3b45f799
User & Date: rkeene on 2020-04-28 18:46:29
Other Links: manifest | tags
Context
2020-04-29
00:34
limitlessled_rf v0.1 check-in: 1e49925e09 user: rkeene tags: 0.1, trunk
2020-04-28
18:46
Added README with limited documentation check-in: c50aa58a64 user: rkeene tags: trunk
18:20
Further improved delays check-in: 989cbde578 user: rkeene tags: trunk
Changes

Added README.md version [c4976858c8].







































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
# Python LimitlessLED via RF

Control LimitlessLED bulbs through a directly attached radio.  The radio object must have an interface with a "`transmit`" method that formats messages as an LT8900 would over the air.

## API

### Synopsis

    limitlessled_rf.remote(radio, remote_type, remote_id, message_id = None, config = None) -> instance
    limitlessled_rf.remote.raw_send_button(button_info) -> value
    limitlessled_rf.remote.raw_read_button() -> dictionary
    limitlessled_rf.remote.set_brightness(brightness, zone = None) -> boolean
    limitlessled_rf.remote.set_color(rgb, zone = None) -> boolean
    limitlessled_rf.remote.set_temperature(kelvins, zone = None) -> boolean
    limitlessled_rf.remote.on(zone = None) -> boolean
    limitlessled_rf.remote.off(zone = None, dim = True) -> boolean
    limitlessled_rf.remote.max_brightness(zone = None) -> boolean
    limitlessled_rf.remote.white(zone = None) -> boolean
    limitlessled_rf.remote.pair(zone) -> boolean
    limitlessled_rf.remote.unpair(zone) -> boolean

### Constructor

Construct a LimitlessLED object that uses the specified radio to act as a specific numeric remote for a specific type of LimitlessLED bulb system.

The "`radio`" object is an LT8900 compatible radio interface -- for example the "`lt8900_spi`" package.

The "`remote_type`" parameter is a string which refers to the type of LimitlessLED bulb this remote can control.  Valid values are: "rgbw" or "cct".

The "`message_id`" parameter allows you to set a default initial message\_id.  If this is not supplied a random value is generated.

The "`config`" parameter allows for overriding a bulbs configuration.  Valid keys can be found in the "`_remote_type_parameters_map`" map.

### instance.raw\_send\_button

Send a button event directly via the locally connected radio to a remote bulb.

The "`button_info`" dictionary contains at least the "`button`" key which identifies the button by name.  Additional keys may be needed depending on the particular button.

### instance.raw\_read\_button

Wait for a button to be pressed that the locally connected radio can read and then return that as a parsed "`button_info`" dictionary.

### instance\.set\_brightness

Set the brightness for the bulbs paired to the specified zone.  Brightness ranges from 0 (off) to 255 (maximum brightness).

If no zone is specified all bulbs attached to the remote are updated.

### instance.set\_color

Set the color for the bulbs paired to the specified zone.  The "`rgb`" parameter is a 16-bit true-color value ranging from 0x000000 (black) to 0xffffff (white).  Since LimitlessLED bulbs
are not actually true-color, this will get mapped to a nearby color before sending it to the bulb.  If the color sent is a shade of white, and the bulb supports white it will be
translated into a brightness.  Otherwise, brightness will not be altered.

If no zone is specified all bulbs attached to the remote are updated.

### instance.set\_temperature

Set the color temperature for the bulbs paired to the specified zone.  The "`kelvins`" parameter refers to the color temperature, in kelvins, that the bulb should be configured to display.
Since LimitlessLED bulbs do not support infinite color temperatures, it will clamped to the range supported and to the nearest color temperature supported before sending the command
to the bulb.

If no zone is specified all bulbs attached to the remote are updated.

### instance.on

Turn on bulbs in the specified zone.

If no zone is specified all bulbs attached to the remote are updated.

### instance.off

Turn off bulbs in the specified zone.

If no zone is specified all bulbs attached to the remote are updated.

### instance.white

Turn the bulbs in the specified zone to their white mode.

If no zone is specified all bulbs attached to the remote are updated.

### instance.pair

Issue the bulb-specific kind of pairing sequence to pair a newly powered-on bulb to this remote on the specified zone.

### instance.unpair

Issue the bulb-specific kind of unpairing sequence to unpair a newly powered-on bulb from this remote on the specified zone.  The bulb must already be paired with this remote and in
the zone before it can be unpaired.  Once a bulb is unpaired from a given remote, it is unpaired from all remotes.

## Example

    #! /usr/bin/env python3
    
    import random
    import time
   
    import gpiozero
    import limitlessled_rf
    import lt8900_spi
    
    def init_radio():
    	# Need to keep this attached to drive the line high -- if the object disappears then
    	# the GPIO port gets reconfigured as an input port
    	# Note: broadcom pin numbers are used
    	reset_gpio = gpiozero.LED(24)
    	reset_gpio.on()
    	def reset_module_via_gpio():
    		reset_gpio.off()
    		time.sleep(0.1)
    		reset_gpio.on()
    		time.sleep(0.1)
    
    	# LT8900 compatible radio
    	radio = lt8900_spi.radio(0, 0, {
    		'reset_command': reset_module_via_gpio,
    		'reset_command_gpio': reset_gpio
    	})
    
    	if not radio.initialize():
    		return None
    
    	return radio
    
    radio = init_radio()
    remote = limitlessled_rf.remote(radio, 'rgbw', 0x51F0)
    
    while True:
    	remote.set_color(random.randint(0, 0xffffff))

Modified __init__.py from [42d9b40b13] to [796fb9f34b].

455
456
457
458
459
460
461










462
463
464
465
466
467
468

	def _step_temperature(self, temperature, temperature_min, temperature_max, zone = None):
		# Select the appropriate zone before sending the steps
		# to ensure they reach the correct bulbs
		self.on(zone, try_hard = False)
		return self._step_value(temperature, temperature_min, temperature_max, 'temperature', zone)











	def _rgb_to_hue(self, r, g, b):
		r = r / 255.0
		g = g / 255.0
		b = b / 255.0

		cmax = max(r, max(g, b))
		cmin = min(r, min(g, b))







>
>
>
>
>
>
>
>
>
>







455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478

	def _step_temperature(self, temperature, temperature_min, temperature_max, zone = None):
		# Select the appropriate zone before sending the steps
		# to ensure they reach the correct bulbs
		self.on(zone, try_hard = False)
		return self._step_value(temperature, temperature_min, temperature_max, 'temperature', zone)

	def _max_brightness(self, zone = None):
		if zone is None:
			message = {'button': 'max'}
		else:
			message = {
				'button': 'zone_max',
				'zone': zone
			}
		return self._send_button(message)

	def _rgb_to_hue(self, r, g, b):
		r = r / 255.0
		g = g / 255.0
		b = b / 255.0

		cmax = max(r, max(g, b))
		cmin = min(r, min(g, b))
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
		self._debug("Setting brightness to {}".format(brightness))
		if brightness == 0:
			self._debug("Really setting to off")
			return self.off(zone)

		if brightness == 255:
			if 'has_max_brightness' in self._config['features']:
				return self.max_brightness(zone)

		brightness_min = self._config['brightness_range'][0]
		brightness_max = self._config['brightness_range'][1]

		brightness = self._scale_int(brightness, 1, 255, self._config['brightness_range'][0], self._config['brightness_range'][1])

		if 'can_set_brightness' in self._config['features']:







|







536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
		self._debug("Setting brightness to {}".format(brightness))
		if brightness == 0:
			self._debug("Really setting to off")
			return self.off(zone)

		if brightness == 255:
			if 'has_max_brightness' in self._config['features']:
				return self._max_brightness(zone)

		brightness_min = self._config['brightness_range'][0]
		brightness_max = self._config['brightness_range'][1]

		brightness = self._scale_int(brightness, 1, 255, self._config['brightness_range'][0], self._config['brightness_range'][1])

		if 'can_set_brightness' in self._config['features']:
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648

		# Increase retries and delay for on/off to ensure
		# that these important messages are delivered
		if try_hard:
			message['retries'] = self._config['retries'] * 2
			message['delay'] = self._config['delay'] * 2

		return self._send_button(message)

	def max_brightness(self, zone = None):
		if 'has_max_brightness' not in self._config['features']:
			return self.set_brightness(255, zone)
			
		if zone is None:
			message = {'button': 'max'}
		else:
			message = {
				'button': 'zone_max',
				'zone': zone
			}
		return self._send_button(message)

	def white(self, zone = None):
		# If the bulbs are already white, nothing needs to be done
		if 'is_white' in self._config['features']:
			return True








<
<
<
<
<
<
<
<
<
<
<
<
<







632
633
634
635
636
637
638













639
640
641
642
643
644
645

		# Increase retries and delay for on/off to ensure
		# that these important messages are delivered
		if try_hard:
			message['retries'] = self._config['retries'] * 2
			message['delay'] = self._config['delay'] * 2














		return self._send_button(message)

	def white(self, zone = None):
		# If the bulbs are already white, nothing needs to be done
		if 'is_white' in self._config['features']:
			return True