GithubHelp home page GithubHelp logo

pylutron-caseta's People

Contributors

b1223gs87 avatar bdraco avatar bostaunieux avatar bpaauwe avatar cbw avatar cdce8p avatar danaues avatar djj211 avatar dkulla01 avatar guoyiang avatar gurumitts avatar johninaustin avatar jonoberheide avatar jordancoleman avatar kfcook avatar mdonoughe avatar michaelgaultjr avatar rhwood avatar samdoran avatar shadowdoc avatar sneelco avatar swails avatar swamplynx avatar thinkelastic avatar upsert avatar yourmom11 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pylutron-caseta's Issues

get_lutron_cert.py remote_signs_app_certificate error

I'm unable to successfully run this script. I always get the following error:

Traceback (most recent call last):
  File "get_lutron_cert.py", line 78, in <module>
    with open('caseta.crt', 'rb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'caseta.crt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "get_lutron_cert.py", line 125, in <module>
    app_cert = pairing_response["remote_signs_app_certificate"]
KeyError: 'remote_signs_app_certificate'

I've tried running this on two separate Ubuntu Servers (18.04). Instructions in the script were followed exactly. I've been able to run this before but as of today this doesn't work.

Any advice on how I can get this working?

Latest changes have broken home assistant

See home-assistant/core#42653 - I can reproduce the problem (HA can receive and update light statuses but can't send any commands to the Lutron Smart Bridge).

I think it boils down to the client tag not being used correctly in this library. The intent behind the client tag is that each client uses the same tag for every single request. We should pick something like PYLUTRON_CASETA or something recognizable rather than a random GUID each time. It also means we can't use the client tag in order to recognize responses to specific requests.

Fun fact, some Lutron devices (like connect bridges) actually have a maximum number of distinct clients that can connect due to the nature of the legacy hardware that it interacts with (HWQS Proc and RRA2 Main Repeater), and after a fairly small number of messages actually starts rejecting everything.

What's the process for cutting a new release?

#41 added support for occupancy sensors, which I plan to add support for in Home Assistant. However, that would require pinning to a pylutron-caseta release that supports occupancy sensors/groups, which doesn't currently exist.

What needs to be done to cut a new release? And when it happens, can it be 0.6.0 (so at least I know what to pin in the home assistant PR I plan on raising soon)?

Device name uses incomplete name.

device_name = device['Name']

Device name is assigned the Name value from the devices dict, however, the FullyQualifiedName would be more appropriate as the latest Lutron Caseta app enforces the use of Rooms. The room name is the prefix the FullyQualifiedName and left out of Name. This leads to multiple switches/dimmers named Light or Lights vs Kitchen Lights, Kitchen Table Lights.

Changing line 321 to device_name = " ".join(device["FullyQualifiedName"]) seems more appropriate.

component failed to setup with KeyError: 'Body'

Caseta component setup failed after I upgraded to home assistant 0.108.0.dev20200330, with below exception.

2020-03-31 18:41:26 ERROR (MainThread) [homeassistant.setup] Error during setup of component lutron_caseta
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/setup.py", line 171, in _async_setup_component
    hass, processed_config
  File "/usr/src/homeassistant/homeassistant/components/lutron_caseta/__init__.py", line 53, in async_setup
    await bridge.connect()
  File "/usr/local/lib/python3.7/site-packages/pylutron_caseta/smartbridge.py", line 51, in connect
    await self._login()
  File "/usr/local/lib/python3.7/site-packages/pylutron_caseta/smartbridge.py", line 363, in _login
    await self._load_occupancy_groups()
  File "/usr/local/lib/python3.7/site-packages/pylutron_caseta/smartbridge.py", line 467, in _load_occupancy_groups
    for occgroup in occgroup_json["Body"]["OccupancyGroups"]:
KeyError: 'Body'

Subscribing to Pico Remotes and Plug-In Dimmers does nothing

Currently trying to get my Philips Hue bulbs to be controllable from my Pico Remote, however this library doesn't quite behave how I'd expect.

Here's a short sample of what I'm attempting:

from pylutron_caseta import smartbridge
import time
import asyncio

async def main():
    bridge = smartbridge.Smartbridge.create_tls("<ip>", "caseta.key", "caseta.crt", "caseta-bridge.crt")
    await bridge.connect()
    picos = bridge.get_devices_by_type("Pico3ButtonRaiseLower")
    assert(len(picos) > 0)
    [bridge.add_subscriber(pico['device_id'], lambda: print("Hello from Pico")) for pico in picos]
    while True:
        time.sleep(1)

asyncio.run(main())

I have two Pico remotes, which I've verified can be seen on the Bridge with the get_devices() method. I've also tried my PlugInDimmer. It does not appear that button presses trigger the callback registered as a subscriber.

Pico Remote buttons recently stopped working in HA integration lutron_caseta

I filed this issue under the lutron_caseta integration in Home Assistant. It was suggested I report the issue here, but add debug log data.

Summary:
I’m using the internal Lutron Caseta integration. In the last 2-3 weeks, my Pico Remote buttons are no longer enabled within the integration. This integration is connected to my Lutron Hub Pro2 (L-BDGPRO2-WH).

When I use "Listen for Events" in the Developer tools page for "lutron_caseta_button_event"s, I see no events firing for Pico Button presses.

I have no issues with Lutron wall switches attached to this hub. The wall switches and the Pico remote buttons show up in the HA integration properly as “devices” (Qty 7), but there are no “entities” associated with the Pico devices only the wall switch devices (Qty 3). One of my Lutron devices is a Ceiling fan controller that has a switch/relay function and buttons to adjust the speed. Only the switch is visible from the integration.

The full debug log is attached below as a text file, but the one Error level message logged is:

ERROR (MainThread) [pylutron_caseta.smartbridge] Failed device status subscription: Response(Header=ResponseHeader(StatusCode=ResponseStatus(400, 'BadRequest'), Url='/button/101/status/event', MessageBodyType='ExceptionDetail'), CommuniqueType='ExceptionResponse', Body={'Message': 'This request is not supported'})

I created this log file with $ cat home-assistant.log | grep pylutron > pylutron.log while logging level was set to DEBUG. Let me know if more/other log data would help.

pylutron.log

Timeout error not trapped?

After receiving this timeout error, smartbridge.is_connected still says connected?

2020-04-03 19:56:46,242 [Controller] [INFO ] is_connected=True
2020-04-03 19:56:46,242 [Controller] [DEBUG] set_value: {'CommuniqueType': 'CreateRequest', 'Header': {'Url': '/zone/5/commandprocessor'}, 'Body': {'Command': {'CommandType': 'GoToLevel', 'Parameter': [{'Type': 'Level', 'Value': 0}]}}}
2020-04-03 19:56:46,243 [Controller] [DEBUG] sending b'{"CommuniqueType": "CreateRequest", "Header": {"Url": "/zone/5/commandprocessor"}, "Body": {"Command": {"CommandType": "GoToLevel", "Parameter": [{"Type": "Level", "Value": 0}]}}}'
2020-04-03 19:56:46,244 [Controller] [ERROR] Fatal write error on socket transport
protocol: <asyncio.sslproto.SSLProtocol object at 0x75863d90>
transport: <_SelectorSocketTransport fd=11 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "/usr/lib/python3.7/asyncio/selector_events.py", line 857, in write
    n = self._sock.send(data)
TimeoutError: [Errno 110] Connection timed out

Note that the "sending" line is from
https://github.com/gurumitts/pylutron-caseta/blob/dev/pylutron_caseta/leap.py#L88

How should this be handled? Is there any way for the caller to know that the command failed?

Cannot control device state

Just trying out the repo for the first time. I have Git #2b9969cd checked out and installed. I pulled my certs fine, wrote a script to fetch device info, which successfully connects and enumerates all of my devices. However, the device state is incorrect and I cannot control anything. Commands appear to get executed but devices don't do anything. I also have Home Assistant set up and that's able to control devices fine using the same certs. Thoughts?

Script:

import asyncio
import logging

HUB_IP_ADDRESS='192.168.0.xx'
bridge = 0
  
async def lutron():
  global bridge
  import pylutron_caseta
  from pylutron_caseta.smartbridge import Smartbridge
  bridge = Smartbridge.create_tls(HUB_IP_ADDRESS, '../caseta.key', '../caseta.crt', '../caseta-bridge.crt')
  await bridge.connect()
  print("Connected: " + str(bridge.is_connected()))
  
  device = bridge.get_device_by_id('31')
  print(device)
      
  bridge.set_value(device['device_id'], 0)

  await bridge.close()

  
logging.basicConfig(filename='lutron_debug.log', filemode='w', level=logging.DEBUG)
asyncio.get_event_loop().run_until_complete(lutron())

stdout:

kwolfe@linux-services:~/pylutron-caseta/tests$ python3 my_test.py
Connected: True
{'device_id': '31', 'current_state': -1, 'fan_speed': None, 'zone': '22', 'name': 'Office_Main Lights', 'type': 'WallDimmer', 'model': 'PD-6WCL-XX', 'serial': 50979658}

Log info (tail -7):

DEBUG:pylutron_caseta.leap:sending b'{"CommuniqueType": "ReadRequest", "Header": {"Url": "/zone/21/status"}}'
DEBUG:pylutron_caseta.smartbridge:Requesting zone information from {'device_id': '31', 'current_state': -1, 'fan_speed': None, 'zone': '22', 'name': 'Office_Main Lights', 'type': 'WallDimmer', 'model': 'PD-6WCL-XX', 'serial': 50979658}
DEBUG:pylutron_caseta.leap:sending b'{"CommuniqueType": "ReadRequest", "Header": {"Url": "/zone/22/status"}}'
DEBUG:pylutron_caseta.smartbridge:Requesting zone information from {'device_id': '32', 'current_state': -1, 'fan_speed': None, 'zone': '23', 'name': 'Office_Ceiling Fan', 'type': 'CasetaFanSpeedController', 'model': 'PD-FSQN-XX', 'serial': 35830569}
DEBUG:pylutron_caseta.leap:sending b'{"CommuniqueType": "ReadRequest", "Header": {"Url": "/zone/23/status"}}'
DEBUG:pylutron_caseta.leap:sending b'{"CommuniqueType": "CreateRequest", "Header": {"Url": "/zone/22/commandprocessor"}, "Body": {"Command": {"CommandType": "GoToLevel", "Parameter": [{"Type": "Level", "Value": 0}]}}}'
INFO:pylutron_caseta.smartbridge:Processing Smartbridge.close() call

async_pair: [Errno13] Permission Denied

Problem

Calling await async_pair(SERVER_ADDRESS) always returns a permission error regardless of the server address validity. However using get_lutron_cert.py with the same address works perfectly fine.

Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.752.0_x64__qbz5n2kfra8p0\lib\concurrent\futures\_base.py", line 446, in result
    return self.__get_result()
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.752.0_x64__qbz5n2kfra8p0\lib\concurrent\futures\_base.py", line 391, in __get_result
    raise self._exception
  File "<console>", line 1, in <module>
  File "C:\Users\TGN-PC\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pylutron_caseta\pairing.py", line 63, in async_pair
    csr, key_bytes_pem, ssl_context = await loop.run_in_executor(
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.752.0_x64__qbz5n2kfra8p0\lib\concurrent\futures\thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "C:\Users\TGN-PC\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\pylutron_caseta\pairing.py", line 205, in _generate_csr_with_ssl_context
    ssl_context.load_cert_chain(lap_cert_temp_file.name, lap_key_temp_file.name)
PermissionError: [Errno 13] Permission denied

Steps to reproduce

  1. Open python REPL with asyncio module
$ python -m asyncio
  1. Import async_pair
>>> from pylutron_caseta.pairing import async_pair
  1. Call async_pair with a valid or invalid server address
>>> await async_pair("192.168.1.255")

Information

OS: Windows 10 Pro
OS Version: 21H1
Python: 3.10.2

Should debug be set?

In the released smartbridge.py code I see _LOG.setLevel(logging.DEBUG) which causes the log file to grow. Is this deliberate or a leak from testing?

Bridge Reconnect during set_value is faing

I'm updating the ISY nodeserver written by @timekillerj and referencing your dev branch for testing. It all works great until it needs to reconnect to the bridge. The call below is executing:
return self.controller.mainloop.run_until_complete(self.sb.set_value(device, value))
But fails with BridgeDisconnectedError even though it says reconnect is happening? Is this a bug or am I doing something wrong?

2020-10-03 18:16:35,709 Controller polyinterface      INFO     LutronCasetaNodes:send_command: send_command result: None
2020-10-03 19:23:44,111 Controller polyinterface      INFO     LutronCasetaNodes:setClose: setClose: command {'address': 'device8', 'cmd': 'DOF', 'query': {}}
2020-10-03 19:23:44,111 Controller polyinterface      INFO     LutronCasetaNodes:send_command: Sending value to Smart Bridge for device 8: 0
2020-10-03 19:23:44,112 Controller polyinterface      INFO     LutronCasetaNodes:send_command: is_connected=True
2020-10-03 19:23:44,114 Controller pylutron_caseta.leap DEBUG    leap:request: sending b'{"CommuniqueType": "CreateRequest", "Header": {"ClientTag": "b45c573b-19d3-4bf9-8ffd-b84f6a816e22", "Url": "/zone/4/commandprocessor"}, "Body": {"Command": {"CommandType": "GoToLevel", "Parameter": [{"Type": "Level", "Value": 0}]}}}'
2020-10-03 19:23:44,116 Controller pylutron_caseta.leap DEBUG    leap:request: sending b'{"CommuniqueType": "ReadRequest", "Header": {"ClientTag": "600479c8-72e6-4990-9edf-b39cee083173", "Url": "/server/1/status/ping"}}'
2020-10-03 19:23:44,117 Controller pylutron_caseta.smartbridge WARNING  smartbridge:_monitor_once: LEAP session ended. Reconnecting...
2020-10-03 19:23:46,120 Controller pylutron_caseta.smartbridge DEBUG    smartbridge:_monitor_once: Connecting to Smart Bridge via SSL
2020-10-03 19:23:46,127 Controller polyinterface      ERROR    polyinterface:_parseInput: _parseInput: failed device8.runCmd(DOF) name 'pylutron_caseta' is not defined
Traceback (most recent call last):
  File "/home/pi/development/udi-poly-lutroncaseta/lutron_caseta_nodes/LutronCasetaNodes.py", line 30, in set_value
    return self.controller.mainloop.run_until_complete(self.sb.set_value(device, value))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/home/pi/development/udi-poly-lutroncaseta/pylutron_caseta/smartbridge.py", line 282, in set_value
    "Parameter": [{"Type": "Level", "Value": value}],
  File "/home/pi/development/udi-poly-lutroncaseta/pylutron_caseta/smartbridge.py", line 235, in _request
    timeout=REQUEST_TIMEOUT,
  File "/usr/lib/python3.7/asyncio/tasks.py", line 416, in wait_for
    return fut.result()
  File "/home/pi/development/udi-poly-lutroncaseta/pylutron_caseta/leap.py", line 60, in request
    return await future
pylutron_caseta.BridgeDisconnectedError

Got exception from unsolicited message handler

I've started seeing these errors pretty frequently in Home Assistant (version 2021.1.5). The only resolution is to restart Home Assistant until it works again.

Logger: homeassistant.config_entries
Source: components/lutron_caseta/__init__.py:75
First occurred: 11:49:04 AM (1 occurrences)
Last logged: 11:49:04 AM
Error setting up entry Caséta bridge for lutron_caseta

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/config_entries.py", line 236, in async_setup
    result = await component.async_setup_entry(hass, self)  # type: ignore
  File "/usr/src/homeassistant/homeassistant/components/lutron_caseta/__init__.py", line 75, in async_setup_entry
    await bridge.connect()
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 100, in connect
    await self._login_completed
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 511, in _login
    await self._load_devices()
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 552, in _load_devices
    device_json = await self._request("ReadRequest", "/device")
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 233, in _request
    response = await asyncio.wait_for(
  File "/usr/local/lib/python3.8/asyncio/tasks.py", line 501, in wait_for
    raise exceptions.TimeoutError()
asyncio.exceptions.TimeoutError

Logger: pylutron_caseta.leap
Source: /usr/local/lib/python3.8/site-packages/pylutron_caseta/leap.py:112
First occurred: 11:54:25 AM (1 occurrences)
Last logged: 11:54:25 AM
Got exception from unsolicited message handler

Traceback (most recent call last):

  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/leap.py", line 110, in run
    handler(obj)
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 506, in _handle_unsolicited
    self._handle_one_zone_status(response)
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 470, in _handle_one_zone_status
    device = self.get_device_by_zone_id(zone)
  File "/usr/local/lib/python3.8/site-packages/pylutron_caseta/smartbridge.py", line 181, in get_device_by_zone_id
    raise KeyError(f"No device associated with zone {zone_id}")
KeyError: 'No device associated with zone 16'

Add telnet support for Smart Bridge Pro

TODO: Add telnet support to support events from Pico remotes on the Smart Bridge Pro. Also needed to support arbitrary fade and/or delay time on any dimmer commands.

A hybrid of SSH and Telnet needs to be supported to get the best features from both types of Smart Bridges. After initial configuration, only one of the interfaces needs to be monitored for events (Telnet for Pro, SSH for non-Pro).

Pro bridge support through the Telnet interface adds a tremendous value by supporting any Pico as a scene controller and in combination with Home Assistant, can trigger any automation. For example, a four button Pico could be used as a fan speed controller with a Z-Wave fan switch.

Support for multi-scene keypads

I have this Pico 4-button remote that triggers four different scenes. The associated scenes are defined from within the device settings in the app, not from the "Scenes" tab. They are also backed by a different smart bridge response format:

{
	'href': '/vbutton/4',
	'ButtonNumber': 1,
	'ProgrammingModel': {
		'href': '/programmingmodel/125'
	},
	'Parent': {
		'href': '/area/6'
	},
	'IsProgrammed': True,
	'Category': {
		'Type': 'Kitchen',
		'SubType': 'Bright'
	}
}

This causes the following error when loading scenes:

2019-09-08 01:58:38 ERROR (MainThread) [homeassistant.setup] Error during setup of component lutron_caseta
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/setup.py", line 168, in _async_setup_component
    hass, processed_config
  File "/usr/src/homeassistant/homeassistant/components/lutron_caseta/__init__.py", line 53, in async_setup
    await bridge.connect()
  File "/usr/local/lib/python3.7/site-packages/pylutron_caseta/smartbridge.py", line 40, in connect
    yield from self._login()
  File "/usr/local/lib/python3.7/site-packages/pylutron_caseta/smartbridge.py", line 285, in _login
    yield from self._load_scenes()
  File "/usr/local/lib/python3.7/site-packages/pylutron_caseta/smartbridge.py", line 351, in _load_scenes
    scene_name = scene['Name']
KeyError: 'Name'

Also, the /vbutton/N numbers conflict with the /virtualbutton/N numbers of my normal lighting scenes, so in order to fully fix, I need to modify activate_scene to be aware of whether it's dealing with a vbutton or a virtualbutton and pass the corresponding URL.

I'm happy to make a pull request for this if desired! If making the full change is undesirable for some reason, at minimum I'd like to add a try/catch to skip scenes that cause this KeyError.

PS: The smart bridge unit tests all fail for me under Python 3.7. Updating them to async/await syntax makes them pass. Should I make a PR for that as well?

Add support to enable/disable Smart Away

While looking into how to control Smart Away's enablement via automations in Home Assistant, it looks like it is possible to control this, although its not supported yet. While it's presented as a scene in the app, it is more of a toggle switch. I'm dropping my findings here for now.

Enable request

{
    "Body": {
        "AwayStatus": {
            "href": "/system/away/1/status",
            "EnabledState": "Enabled"
        }
    },
    "CommuniqueType": "UpdateRequest",
    "Header": {
        "Url": "/system/away/1/status"
    }
}

Disable request

{
    "Body": {
        "AwayStatus": {
            "href": "/system/away/1/status",
            "EnabledState": "Disabled"
        }
    },
    "CommuniqueType": "UpdateRequest",
    "Header": {
        "Url": "/system/away/1/status"
    }
}

The Bridge responds similar to the below

{
	'AwayStatus': {
		'href': '/system/away/1/status',
		'EnabledState': 'Disabled',
		'ActiveState': 'Inactive'
	}
}

Subscribe

{
    "CommuniqueType": "SubscribeRequest",
    "Header": {
        "Url": "/system/away/1/status"
    }
}

The notification matches the Bridge response to the request.

Certificate Generation Failing

Problem

Calling await async_pair(SERVER_ADDRESS) always returns an SSL failure: verify failed: self signed certificate in certificate chain

File "/Users/mike/coding/pylutron-caseta/do_pairing.py", line 171, in async_pair
cert_pem, ca_pem = await _async_generate_certificate(
File "/Users/mike/coding/pylutron-caseta/do_pairing.py", line 205, in _async_generate_certificate
reader, writer = await asyncio.wait_for(
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/tasks.py", line 478, in wait_for
return fut.result()
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/streams.py", line 52, in open_connection
transport, _ = await loop.create_connection(
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 1081, in create_connection
transport, protocol = await self._create_connection_transport(
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 1111, in _create_connection_transport
await waiter
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/sslproto.py", line 528, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/sslproto.py", line 188, in feed_ssldata
self._sslobj.do_handshake()
File "/usr/local/Cellar/[email protected]/3.9.1/Frameworks/Python.framework/Versions/3.9/lib/python3.9/ssl.py", line 944, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1123)

Steps to reproduce

  1. Open python REPL with asyncio module
    $ python -m asyncio
  2. Import async_pair
    >>> from pylutron_caseta.pairing import async_pair
  3. Call async_pair with a valid or invalid server address
    >>> await async_pair("192.168.1.255")

Information

OS: Mac Big Sur 11.3.1
OS Version: 11.3.1
Python: 3.9.1

Lights lack SUPPORT_TRANSITION

I noticed that Lutron Caseta specificially lacks the SUPPORT_TRANSITION effects, yet the Lutron Caseta dimmers definitely seem to have support.

Docs?

I'm trying to control my smart bridge pro, found this project, but can't find any docs on how to get it going. Please help!

Does smartbridge add_button_subscriber API work?

I have the following prototype code (below), which is able to communicate with my bridge, but the add_subscriber API appears to do nothing. Here is the tail end of the output (below). As can be seen - I'm able to communicate with the bridge correctly. but it seems the add_subscriber does nothing, or I have a bug in the way I'm using it.

I am pushing the various buttons on the pico remote attempting to get the callback to fire, but nothing seems to happen.

I should mention - I'm not a python developer in my day-job, so there could be silly bugs due to my lack of understanding of some python basics.

Does the add_subscriber API work?

15-Feb-22 08:15:46 - dumping device: {'device_id': '1', 'current_state': -1, 'fan_speed': None, 'zone': None, 'name': 'Smart Bridge 2', 'button_groups': None, 'type': 'SmartBridge', 'model': 'L-BDG2-WH', 'serial': 75327547}
15-Feb-22 08:15:46 - dumping device: {'device_id': '2', 'current_state': 50, 'fan_speed': None, 'zone': '1', 'name': 'Kitchen_Pendants', 'button_groups': None, 'type': 'WallDimmer', 'model': 'PD-6WCL-XX', 'serial': 65992296}
15-Feb-22 08:15:46 - dumping device: {'device_id': '3', 'current_state': -1, 'fan_speed': None, 'zone': None, 'name': 'Kitchen_OliotPico', 'button_groups': ['2'], 'type': 'Pico3ButtonRaiseLower', 'model': 'PJ2-3BRL-GXX-X01', 'serial': 66761298}
15-Feb-22 08:15:46 - FOUND Pico: {'device_id': '3', 'current_state': -1, 'fan_speed': None, 'zone': None, 'name': 'Kitchen_OliotPico', 'button_groups': ['2'], 'type': 'Pico3ButtonRaiseLower', 'model': 'PJ2-3BRL-GXX-X01', 'serial': 66761298}
15-Feb-22 08:15:46 - Added subscriber to button with device_id: 3
15-Feb-22 08:15:46 - sleeping...
15-Feb-22 08:15:51 - sleeping...
15-Feb-22 08:15:56 - sleeping...
#!/usr/bin/env python3

import sys
import logging
import asyncio
import time

from oliot.config import Config

logging.basicConfig(
    format='%(asctime)s - %(message)s',
    datefmt='%d-%b-%y %H:%M:%S',
    level=logging.DEBUG,
    stream=sys.stdout
)
log = logging.getLogger(__name__)

config = Config()

# Because pylutron_caseta uses asyncio,
# it must be run within the context of an asyncio event loop.
loop = asyncio.get_event_loop()


global finalized
global bridge

async def example_async_callback(arg1: [str]) -> None:
    log.info("Received async callback: {}".format(arg1))
    await bridge.close()
    global finalized
    finalized = True


def example_callback(arg1: [str]) -> None:
    log.info("Received callback: {}".format(arg1))
    loop.run_until_complete(example_async_callback(arg1))


async def subscribe() -> None:
    global finalized
    finalized = False
    # `Smartbridge` provides an API for interacting with the Caséta bridge.
    bridge = config.lutron.bridge(bridgeId="dh-lutron")
    await bridge.connect()

    devices = bridge.get_devices()
    for key in devices:
        device = devices[key]
        log.info("dumping device: {}".format(device))
        if 'name' in device:
            name = device['name']
            fqn = name.split("_")
            if len(fqn) > 1 and fqn[0] == 'Kitchen' and fqn[1] == 'OliotPico':
                log.info("FOUND Pico: {}".format(device))
                bridge.add_button_subscriber(key, example_callback)
                log.info("Added subscriber to button with device_id: {}".format(key))
                break
        else:
            log.debug("device {} does not have key '{}'".format(key, 'FullyQualifiedName'))

loop.run_until_complete(subscribe())

while not finalized:
    log.info("sleeping...")
    time.sleep(5)

log.info("FINALIZED!")

Question: Does this library work with RadioRA 3 All-in-One Processor?

Does this library work with RadioRA 3 All-in-One Processor model number RR-PROC3-KIT?

I'd like to standardize my systems to use this library. I've confirmed the functionality I need works with the caseta bridge and am considering the RadioRA3 devices - but I don't want to purchase and experiment if anyone definitively knows this library does not work with the RadioRA3 processor.

Working with OpenHAB 3

Working with your script with OH3. The script runs fine and generates the three files. One issue is the script never asked me for a password. Not sure what to tell OH3 for the password.

Anyone using this script with OH3?

Greg

RA3/QSX Button LED Names don't identify the Keypad and Button

@cbw, Amazing work on the QSX support, and for adding LED and button press support.

I've been testing with my setup, and I think it would help to use a more meaningful name for the Keypad LEDs

I have 2 keypads in this area, a 3BRL and a 4B. It's hard to tell which led these belong too.
Ideally they would be named "LED_Hallway Main Stairs_Position 1_Button2" or something like that.

image

Serena Shades support

Hi! Thank you so much for your work on the lutron_caseta component. It's fantastic!

I have two sets of Serena Shades, and I was wondering if there's anything I could do to help add support. Please let me know!

Lutron Caseta firmware updte ?

I think Lutron update his firmware...
The HA component stop working : home-assistant/core#15421

Why get_lutron_certificate.py, if i dump the json result of the test request, i got that :

{'Header': {'StatusCode': '204 NoContent', 'Url': '/device/status/deviceheard'}, 'CommuniqueType': 'SubscribeResponse'}

Having trouble with Python 2 on Win7

I'm the noobiest around, so I might just be doing this incorrectly. I'm on Win7 with Python 2, and this my session:

C:\Python27\Scripts>pip install pyopenssl

C:\Python27\Scripts>python get_lutron_cert.py
get_lutron_cert.py:25: CryptographyDeprecationWarning: Python 2 is no longer sup
ported by the Python core team. Support for it is now deprecated in cryptography
, and will be removed in the next release.
  from cryptography import x509
Traceback (most recent call last):
  File "get_lutron_cert.py", line 38, in <module>
    [x509.NameAttribute(NameOID.COMMON_NAME, "get_lutron_cert.py")]
  File "C:\Python27\lib\site-packages\cryptography\x509\name.py", line 87, in __
init__
    raise TypeError("value argument must be a text type.")
TypeError: value argument must be a text type.

C:\Python27\Scripts>

I know very little and I'm honestly just knocking on the door to see if someone can nudge me in the right direction. I don't know where to go from here.

latency for occupancy sensors?

Hi, I'm trying to diagnose an issue where the occupancy sensor update in HA is 0-3 seconds delayed. I logged the trigger time and action time in HA and found only .03 second delay so my next thought is that the update from the smart bridge might be delayed or picked up late, is there some logging I can do to diagnose this?

Reading the docs on HA website I was under the impression this should be almost instantaneous.

Support for RA2 Select In-Line Dimmer

I have the RA2 Select system I'd like to use with HA. The scenes work within HA so I'm hoping that just adding InLineDimmer and InLineSwitch to _LEAP_DEVICE_TYPES will just work. Only started with HA last night but happy to test something with a bit of guidance.

Here's a snippet from HA's diagnostic:

"data": {
      "devices": {
        "1": {
          "device_id": "1",
          "current_state": -1,
          "fan_speed": null,
          "zone": null,
          "name": "Smart Bridge 2",
          "button_groups": null,
          "type": "RA2SelectMainRepeater",
          "model": "RRK-SEL-REP2-BL",
          "serial": 53030971
        },
        ...
        "6": {
          "device_id": "6",
          "current_state": 0,
          "fan_speed": null,
          "zone": "3",
          "name": "Main Bathroom_Main Lights",
          "button_groups": null,
          "type": "InLineSwitch",
          "model": "RRK-R6ANS-240",
          "serial": 60575713
        },
        ...
        "10": {
          "device_id": "10",
          "current_state": 0,
          "fan_speed": null,
          "zone": "6",
          "name": "Master Bedroom_Main Lights",
          "button_groups": null,
          "type": "InLineDimmer",
          "model": "RRK-R25NE-240",
          "serial": 49259950
        },

License?

Please forgive me if I've just missed it, but this project doesn't appear to have a license attached. Can you please select one and attach it?

reconnection failures

I probably introduced this error somehow. I've noticed that occasionally my home automation will lose its connection to the bridge and I'll get messages like this in my logs:

2018-01-09 07:24:27 DEBUG (MainThread) [pylutron_caseta.smartbridge] Connecting to Smart Bridge via SSL
2018-01-09 07:24:57 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/asyncio/tasks.py", line 180, in _step
    result = coro.send(None)
  File "/usr/local/lib/python3.6/site-packages/pylutron_caseta/smartbridge.py", line 301, in _ping
    self._writer.write({
AttributeError: 'NoneType' object has no attribute 'write'

followed by:

2018-01-09 12:53:28 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: domain=light, service=turn_on, service_data=entity_id=light.upstairs_hub_lights, service_call_id=139889797154184-1056>
2018-01-09 12:53:28 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/asyncio/tasks.py", line 180, in _step
    result = coro.send(None)
  File "/usr/src/app/homeassistant/core.py", line 1031, in _event_to_service_call
    yield from service_handler.func(service_call)
  File "/usr/src/app/homeassistant/components/light/__init__.py", line 271, in async_handle_light_service
    yield from light.async_turn_on(**params)
  File "/usr/local/lib/python3.6/asyncio/coroutines.py", line 210, in coro
    res = func(*args, **kw)
  File "/usr/src/app/homeassistant/components/light/lutron_caseta.py", line 57, in async_turn_on
    to_lutron_level(brightness))
  File "/usr/local/lib/python3.6/site-packages/pylutron_caseta/smartbridge.py", line 182, in set_value
    return self._writer.write(cmd)
AttributeError: 'NoneType' object has no attribute 'write'

every time I try to control the lights until I restart the process.

It happens infrequently enough that I think it could be triggered by Lutron restarting the bridge by pushing out firmware updates or something like that. It looks like maybe the new connection times out?

Homeworks QSX gives 204 No Content errors once logged in

I realize this is somewhat out of scope. But it gets so far that one would think it is may be trivial to complete the picture. Using this tool with Lutron Homeworks QSX gets all the way past auth and past login, but then requests for data like /device and /area all fail with 204 No Content. It feels like this is one tweak away from QSX support, but not sure what it would be. Am I doing something wrong or presumably this is expected?

Trying to find AssociatedDevices on OccupancyGroup instead of Area

I think the concepts of "Area" and "OccupancyGroup" are reversed. From what I'm seeing it's rejecting OccupancyGroups because there are no AssociatedDevice[s] but those are assigned to Area[s].

if not associated_areas:

Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.smartbridge] Loading areas from the Smart Bridge Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.leap] sending b'{"CommuniqueType": "ReadRequest", "Header": {"Url": "/area"}}' Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.leap] received b'{"CommuniqueType":"ReadResponse","Header":{"MessageBodyType":"MultipleAreaDefinition","StatusC ode":"200 OK","Url":"/area"},"Body":{"Areas":[{"href":"/area/1","Name":"root","LoadShedding":{"href":"/area/1/loadshedding"}},{"href":"/area/2","Name":"Dining Room","Parent":{"href":"/area/1"},"Category":{"Ty pe":"DiningRoom"},"AssociatedDevices":[{"href":"/device/2"},{"href":"/device/3"},{"href":"/device/22"},{"href":"/device/24"},{"href":"/device/25"}],"AssociatedOccupancyGroups":[{"href":"/occupancygroup/1"}]," LoadShedding":{"href":"/area/2/loadshedding"},"OccupancySettings":{"href":"/area/2/occupancysettings"},"OccupancySensorSettings":{"href":"/area/2/occupancysensorsettings"},"DaylightingGainSettings":{"href":"/ area/2/daylightinggainsettings"}}, ...

Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.smartbridge] Loading occupancy groups from the Smart Bridge Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.leap] sending b'{"CommuniqueType": "ReadRequest", "Header": {"Url": "/occupancygroup"}}' Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.leap] received b'{"CommuniqueType":"ReadResponse","Header":{"MessageBodyType":"MultipleOccupancyGroupDefinition ","StatusCode":"200 OK","Url":"/occupancygroup"},"Body":{"OccupancyGroups":[{"href":"/occupancygroup/1","AssociatedAreas":[{"Area":{"href":"/area/2"}}],"ProgrammingType":"Freeform","ProgrammingModel":{"href": "/programmingmodel/142"}},{"href":"/occupancygroup/2","AssociatedAreas":[{"Area":{"href":"/area/3"}}],"ProgrammingType":"Freeform","ProgrammingModel":{"href":"/programmingmodel/143"}},{"href":"/occupancygroup /3","AssociatedAreas":[{"Area":{"href":"/area/4"}}],"ProgrammingType":"Freeform","ProgrammingModel":{"href":"/programmingmodel/144"}},{"href":"/occupancygroup/4","AssociatedAreas":[{"Area":{"href":"/area/5"}} ],"ProgrammingType":"Freeform","ProgrammingModel":{"href":"/programmingmodel/145"}},{"href":"/occupancygroup/5","AssociatedAreas":[{"Area":{"href":"/area/6"}}],"ProgrammingType":"Freeform","ProgrammingModel": {"href":"/programmingmodel/146"}},{"href":"/occupancygroup/6","AssociatedAreas":[{"Area":{"href":"/area/7"}}],"ProgrammingType":"Freeform","ProgrammingModel":{"href":"/programmingmodel/157"}},{"href":"/occupa ncygroup/7","AssociatedAreas":[{"Area":{"href":"/area/8"}}],"ProgrammingType":"Freeform","ProgrammingModel":{"href":"/programmingmodel/158"}},{"href":"/occupancygroup/8","AssociatedAreas":[{"Area":{"href":"/a rea/9"}}],"ProgrammingType":"Freeform","ProgrammingModel":{"href":"/programmingmodel/159"}},{"href":"/occupancygroup/9", ... Sep 14 13:32:42 raspberrypi hass[14890]: 2020-09-14 13:32:42 DEBUG (MainThread) [pylutron_caseta.smartbridge] No sensors associated with /occupancygroup/1

New method no longer working?

I appears that something has changed on the Lutron end. Neither the plugin nor the script to get a key are working anymore.

plugin error:
Error during setup of component lutron_caseta Traceback (most recent call last): File "/usr/lib/python3.6/site-packages/homeassistant/setup.py", line 142, in _async_setup_component result = await component.async_setup(hass, processed_config) File "/usr/lib/python3.6/site-packages/homeassistant/components/lutron_caseta.py", line 57, in async_setup yield from bridge.connect() File "/usr/lib/python3.6/site-packages/pylutron_caseta/smartbridge.py", line 40, in connect yield from self._login() File "/usr/lib/python3.6/site-packages/pylutron_caseta/smartbridge.py", line 281, in _login self._reader, self._writer = yield from self._connect() File "/usr/lib/python3.6/site-packages/pylutron_caseta/smartbridge.py", line 58, in _connect family=socket.AF_INET) File "/usr/lib/python3.6/site-packages/pylutron_caseta/leap.py", line 16, in open_connection limit=limit, **kwds) File "/usr/lib/python3.6/asyncio/streams.py", line 75, in open_connection lambda: protocol, host, port, **kwds) File "uvloop/loop.pyx", line 1769, in create_connection File "/usr/lib/python3.6/asyncio/sslproto.py", line 503, in data_received ssldata, appdata = self._sslpipe.feed_ssldata(data) File "/usr/lib/python3.6/asyncio/sslproto.py", line 201, in feed_ssldata self._sslobj.do_handshake() File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake self._sslobj.do_handshake() ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:777)

Script error:
(general) xnappo@machine:~/homeio$ python get_lutron_cert.py Enter the address of your Caseta bridge device: 192.168.1.xx Traceback (most recent call last): File "get_lutron_cert.py", line 156, in <module> leap_response['Body']['PingResponse']['LEAPVersion']) KeyError: 'Body'

Problem creating the files

When I try to run the script, I get this error. Any thoughts? I have installed OpenSSL
root@buzzs-laptop:/home/buzz# python get_lutron_cert.py
Traceback (most recent call last):
File "get_lutron_cert.py", line 31, in
from OpenSSL import SSL, crypto
ImportError: No module named OpenSSL
root@buzzs-laptop:/home/buzz#

get_lutron_cert.py not working

Hello,

I'm trying to use the get_lutron_cert.py script to authorize my casesta hub on my HomeAssistant server. Each time I run the script, I get the following error after I paste the response code from Lutron:

Traceback (most recent call last):
  File "get_lutron_cert.py", line 78, in <module>
    with open('caseta.crt', 'rb') as f:
FileNotFoundError: [Errno 2] No such file or directory: 'caseta.crt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "get_lutron_cert.py", line 124, in <module>
    app_cert = pairing_response["remote_signs_app_certificate"]
KeyError: 'remote_signs_app_certificate'

I'm using the latest version of the script, using python3 on a mac. Does anyone know what is causing this?

Thanks!

Listen to Pico Button Presses

Hi everyone,
How does one listen for pico button presses using this library? I'd like to capture the event in my python code and then do something with it. I've searched high and low and can't quite figure this one out.

Recovering from power outage

It's not clear if this is a Home Assistant or pylutron-caseta issue...

My Caseta bridge had a power outage (a contractor overloaded the circuit and tripped the breaker switch). After rebooted, HA was unable to talk to the bridge and all attempts timed out.

Logs at that time...

2019-04-04 18:17:10 ERROR (MainThread) [homeassistant.core] Error doing job: Fat
al read error on socket transport
Traceback (most recent call last):
  File "/opt/rh/rh-python36/root/usr/lib64/python3.6/asyncio/selector_events.py"
, line 724, in _read_ready
    data = self._sock.recv(self.max_size)
OSError: [Errno 113] No route to host

Restarting the home assistant process fixed the issue.

Feature Request: Add support for sending push/hold events to a Pico

If you have multiple lights or shades controlled by a single remote, those devices move much more synchronously than if you try to recreate the same grouping in something like Home Assistant. For example, I have three window shades controlled by a single Pico. When I use the raise/lower or open/close buttons, they all move in unison. When I create an automation in HA to send a command to three devices, there is a noticeable lag in start time between the devices.

The LEAP protocol supports sending button hrefs the commands PressAndRelease, PressAndHold, and Release -- this is what the mobile app sends when you use it to drive a Pico. The target is the button's href, e.g. /button/125/commandprocessor. A remote's button definition can be retrieved by sending a ReadRequest to the button group's URL, e.g. /buttongroup/7. When the button itself is targeted with PressAndRelease, the bridge sends the commands to the related device in a coordinated manner as described.

The button model in pylutron could be updated to support these commands, and then HA could be updated to make use of the new capabilities as well. There is also a MultiTap command but I don't know what it does, and I don't have any devices that can be configured for multiple tap responses (thinking double/triple taps?)

Refactor for getting devices by HA type

As per comments in home-assistant/core#8903, the Home Assistant authors have suggested having a method to retrieve devices by their HA type such as 'light', 'switch' and 'cover'. The refactor is needed before support for Triathlon shades can be added.

For reference, find below all the device types supported on the LEAP interface. Includes a sensor type in anticipation of one day supporting Pico remotes which will become sensors.

'light'
WallDimmer
PlugInDimmer
'switch'
WallSwitch
'cover'
SerenaHoneycombShade
SerenaRollerShade
TriathlonHoneycombShade
TriathlonRollerShade
QsWirelessShade
'sensor'
Pico1Button
Pico2Button
Pico2ButtonRaiseLower
Pico3Button
Pico3ButtonRaiseLower
Pico4Button
Pico4ButtonScene
Pico4ButtonZone
Pico4Button2Group
FourGroupRemote
Other Device Types
SmartBridge

@gurumitts I hope you don't mind if I add a few issues and if I can learn a bit more Python, hopefully I'll contribute some code too. I'll also try to write up what I've learned about the interfaces.

Support for RF Modules

Hoping support for the following two devices can be added. These devices work across most Lutron systems (RA2, RA2S, RA3).

0-10V RF Dimming Module
Model: LMJ-5T-DV-B

RF Relay Module with Softswitch
Model: LMJ-16R-DV-B

I currently do not have these devices on hand, but can supply them to you if required.

internal device IDs vs zone IDs

Hi,

I have a smartbridge PRO and tried your module. I noticed that all the device IDs were off by one compared to the integration report from the lutron app. I believe that commands actually need to act on zone ids rather than device ids. Here is one of the devices :

        {
            "href": "/device/3",
            "Name": "Cans Livingroom",
            "Parent": {
                "href": "/project"
            },
            "SerialNumber": 26669871,
            "ModelNumber": "PD-6WCL-XX",
            "DeviceType": "WallDimmer",
            "LocalZones": [
                {
                    "href": "/zone/2"
                }
            ]
        }

I believe the command to e.g. turn it off should be :

#OUTPUT,2,1,0

rather than

#OUTPUT,3,1,0

Thanks,
Bijan

entities unavailable after configuration

I recently installed this plugin in my home assistant. While all of the entities show up, they are all listed as unavailable.

The setup is pretty straightforward and succeeded at all steps so I'm unsure what next steps to take to sort through why they aren't working.

Has anyone seen this issue before

Here is an image of the devices. Note the items listed as fans are just luton switches labelled as fans NOT the official Lutron fan device.
Screen+Shot+2020-03-05+at+8 55 52+AM

Feature Request: Add support for all button events

Pull request #81 added support for Pico button events. This allows Home Assistant to use Pico buttons as triggers, which is great for turning these into general purpose remotes for home automation. I would like to see this same functionality added to hardwired switches/dimmers/fan controls as well. There are many use cases for this. Here are a few examples:

Double-tapping OFF on a switch near a door will turn off all lights inside the house.
Double-tapping ON at the garage entry door will turn on all lights leading into the kitchen.
Tapping ON when a light is already on will turn on the rest of the lights in the area.

Is this info available through the Smart Bridge Pro and able to be added?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.