Comments (15)
@tsightler thanks again, I completely understand you need to do something with the Refresh Token Updated event, was just an experiment (that failed). Thanks for explaining the length difference with those tokens.
I think I found the problem. It looks like I reached a certain amount of authorized user devices, I removed them all via account.ring.com and now it all seems to work!
Thanks again for your help.
from ring.
Can you please run Data Discovery and provide the output of both cameras?
Also, are you definitely getting notifications from the second device on your Ring app? Note that I don't mean events. If you could catch a screenshot of a notification from said camera on your phone but not from ring-client-api, that would be interesting.
from ring.
{"locations":[{"name":"Apeldoorn","cameras":[{"kind":"cocoa_doorbell","description":"Backdoor","is_sidewalk_gateway":false,"created_at":"2021-10-16T15:33:21Z","deactivated_at":null,"firmware_version":"Up to Date","owned":true,"stolen":false,"shared_at":null,"health":{"ac_power":0,"battery_percentage":94,"battery_percentage_category":"very_good","battery_present":true,"battery_save":false,"battery_voltage":4169,"battery_voltage_category":"very_good","connected":true,"device_type":"cocoa_doorbell","external_connection":false,"firmware_version":"cam-1.17.11200","floodlight_on":false,"last_update_time":1690982675,"network_connection_value":"wifi","night_mode_on":false,"ota_status":"timeout","rss_connected":true,"rssi":-64,"rssi_category":"okay","second_battery_percentage_category":"unknown","second_battery_voltage_category":"unknown","sidewalk_connection":false,"white_led_on":false,"firmware_version_status":"Up to Date","packet_loss":0,"packet_loss_category":"good","hatch_open":false,"ext_power_state":0,"pref_run_mode":"low_power","run_mode":"low_power","supported_rpc_commands":["ping"],"status_time":55410120257961,"vod_enabled":true,"firmware_avg_bitrate":"2031","video_packets_total":"13296","wifi_is_ring_network":false,"channel":"3","tx_rate":4},"subscribed":true,"subscribed_motions":true,"battery_life":"94","external_connection":false,"active_schedule_uuid":null,"alerts":{"connection":"online","ota_status":"timeout"},"motion_snooze":null,"settings":{"motion_snooze_preset_profile":"none","motion_snooze_presets":["none","low","medium","high"],"live_view_preset_profile":"middle","live_view_presets":["low","middle","high","highest"],"doorbell_volume":8,"chime_settings":{"enable":false,"type":0,"duration":10},"advanced_motion_detection_enabled":true,"advanced_motion_detection_human_only_mode":true,"enable_audio_recording":true,"people_detection_eligible":true,"live_view_disabled":false,"ignore_zones":{"zone1":{"name":"","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}},"zone2":{"name":"","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}},"zone3":{"name":"Zone 3","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}},"zone4":{"name":"Zone 4","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}}},"enable_rich_notifications":true,"rich_notifications_billing_eligible":true,"loitering_threshold":10,"advanced_motion_detection_types":["human"],"motion_detection_enabled":true,"rich_notifications_scene_source":"cloud","offline_motion_event_settings":{"subscribed":true,"enabled":false,"max_upload_kb":5000,"resolution_p":360,"frequency_after_secs":2,"period_after_secs":30},"cv_settings":{"detection_types":{"human":{"enabled":true,"mode":"cloud","record":null,"notification":true},"loitering":{"enabled":false,"mode":"none","record":null,"notification":false},"motion":{"enabled":true,"mode":"cloud","record":null,"notification":false},"moving_vehicle":{"enabled":false,"mode":"none","record":null,"notification":false},"other_motion":{"enabled":false,"mode":"none","record":null,"notification":false},"package_delivery":{"enabled":true,"mode":"cloud","record":null,"notification":true},"package_pickup":{"enabled":false,"mode":"none","record":null,"notification":false}},"threshold":{"loitering":10,"package_delivery":2},"triggers":[]},"concierge_settings":{"mode":"disabled"},"sheila_settings":{"cv_processing_enabled":false,"local_storage_enabled":false},"server_settings":{"ring_media_server_enabled":true,"ring_media_server_host":"rms-eu-west-1.rapi.us-east-1.prod.client.cap.ring.devices.a2z.com"},"cv_paid_features":{"baby_cry":true,"car_alarm":true,"co2_smoke_alarm":true,"dog_bark":true,"general_sound":true,"glass_break":true,"human":true,"loitering":true,"motion":true,"other_motion":true,"package_delivery":true,"package_pickup":true,"cv_triggers":true},"other_paid_features":{"alexa_concierge":true,"sheila_cv":true,"sheila_recording":true},"zone_settings":{"motion":[{"name":"Default Zone","state":"enabled","properties":{"detection_types":["motion"],"style":1},"vertices":[{"x":0,"y":0.701259},{"x":0.185669,"y":0.633002},{"x":0.206613,"y":0.478823},{"x":0.991667,"y":0.471179},{"x":1,"y":1},{"x":0.6721,"y":1},{"x":0.332374,"y":1},{"x":0,"y":1}]},{"name":"Pakketzone","state":"enabled","properties":{"detection_types":["package_delivery"],"style":4},"vertices":[{"x":0.332444,"y":0.75233},{"x":0.39726,"y":0.691044},{"x":0.470194,"y":0.705384},{"x":0.543448,"y":0.692283},{"x":0.480854,"y":0.986426},{"x":0.407402,"y":0.997441},{"x":0.330309,"y":0.997441},{"x":0.086698,"y":1}]}]},"stark_enrolled":null,"network_settings":{"mac_address_ble":null,"max_dynamic_listen_interval":null,"network_diagnosis":null,"multi_net_pref":0,"mac_address_wifi_24":null,"mac_address_wifi_5":null},"motion_zones":[1,1,1,1,0],"enable_vod":1,"exposure_control":2,"vod_suspended":0,"vod_status":"enabled","voice_volume":11,"video_settings":{"encryption_enabled":false,"encryption_method":1,"hevc_enabled":false},"advanced_motion_zones":{"zone1":{"name":"Default Zone","state":2,"vertex1":{"x":0,"y":0.701259},"vertex2":{"x":0.185669,"y":0.633002},"vertex3":{"x":0.206613,"y":0.478823},"vertex4":{"x":0.991667,"y":0.471179},"vertex5":{"x":1,"y":1},"vertex6":{"x":0.6721,"y":1},"vertex7":{"x":0.332374,"y":1},"vertex8":{"x":0,"y":1}},"zone2":{"name":"Zone 2","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0},"vertex3":{"x":0,"y":0},"vertex4":{"x":0,"y":0},"vertex5":{"x":0,"y":0},"vertex6":{"x":0,"y":0},"vertex7":{"x":0,"y":0},"vertex8":{"x":0,"y":0}},"zone3":{"name":"Zone 3","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0},"vertex3":{"x":0,"y":0},"vertex4":{"x":0,"y":0},"vertex5":{"x":0,"y":0},"vertex6":{"x":0,"y":0},"vertex7":{"x":0,"y":0},"vertex8":{"x":0,"y":0}}},"advanced_motion_zones_enabled":true,"advanced_motion_zones_type":"8vertices","advanced_pir_motion_zones":{"zone1_sensitivity":5,"zone2_sensitivity":5,"zone3_sensitivity":5,"zone4_sensitivity":5,"zone5_sensitivity":5,"zone6_sensitivity":5},"pir_sensitivity_1":4,"lite_24x7":{"subscribed":true,"enabled":true,"frequency_secs":300,"resolution_p":360},"rich_notifica-uuid":false},"features":{"cfes_eligible":true,"motion_zone_recommendation":false,"motions_enabled":true,"show_recordings":true,"show_vod_settings":true,"rich_notifications_eligible":true,"show_offline_motion_events":false,"sheila_camera_eligible":true,"sheila_camera_processing_eligible":true,"dynamic_network_switching_eligible":false,"chime_auto_detect_capable":false,"show_24x7_lite":true},"ext_power_state":0},{"kind":"cocoa_doorbell_v2","description":"Frontdoor","is_sidewalk_gateway":false,"created_at":"2023-06-24T13:55:39Z","deactivated_at":null,"firmware_version":"Up to Date","owned":true,"stolen":false,"shared_at":null,"health":{"ac_power":1,"battery_percentage":96,"battery_percentage_category":"very_good","battery_present":true,"battery_save":false,"battery_voltage":4030,"battery_voltage_category":"very_good","connected":true,"device_type":"cocoa_doorbell_v2","external_connection":true,"firmware_version":"cam-1.4.16200","floodlight_on":false,"last_update_time":1690982192,"network_connection_value":"wifi","night_mode_on":false,"ota_status":"timeout","rss_connected":true,"rssi":-59,"rssi_category":"good","second_battery_percentage_category":"unknown","second_battery_voltage_category":"unknown","sidewalk_connection":false,"white_led_on":false,"firmware_version_status":"Up to Date","packet_loss":0,"packet_loss_category":"good","hatch_open":false,"ext_power_state":3,"pref_run_mode":"low_power","run_mode":"low_power","supported_rpc_commands":["ping"],"status_time":55410104514586,"vod_enabled":true,"firmware_avg_bitrate":"2003","video_packets_total":"1586","wifi_is_ring_network":false,"channel":"3","tx_rate":4},"subscribed":true,"subscribed_motions":true,"battery_life":"96","external_connection":true,"active_schedule_uuid":null,"alerts":{"connection":"online","ota_status":"timeout"},"motion_snooze":null,"settings":{"motion_snooze_preset_profile":"none","motion_snooze_presets":["none","low","medium","high"],"live_view_preset_profile":"middle","live_view_presets":["low","middle","high","highest"],"doorbell_volume":8,"chime_settings":{"enable":false,"type":0,"duration":10},"advanced_motion_detection_enabled":true,"advanced_motion_detection_human_only_mode":true,"enable_audio_recording":true,"people_detection_eligible":true,"live_view_disabled":false,"ignore_zones":{"zone1":{"name":"undefined","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}},"zone2":{"name":"undefined","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}},"zone3":{"name":"undefined","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}},"zone4":{"name":"undefined","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0}}},"enable_rich_notifications":true,"rich_notifications_billing_eligible":true,"loitering_threshold":10,"advanced_motion_detection_types":["human"],"motion_detection_enabled":true,"rich_notifications_scene_source":"firmware","offline_motion_event_settings":{"subscribed":true,"enabled":false,"max_upload_kb":5000,"resolution_p":360,"frequency_after_secs":2,"period_after_secs":30},"cv_settings":{"detection_types":{"human":{"enabled":true,"mode":"edge","record":null,"notification":true},"loitering":{"enabled":false,"mode":"none","record":null,"notification":false},"motion":{"enabled":true,"mode":"edge","record":null,"notification":false},"moving_vehicle":{"enabled":false,"mode":"none","record":null,"notification":false},"other_motion":{"enabled":false,"mode":"none","record":null,"notification":false},"package_delivery":{"enabled":true,"mode":"edge","record":null,"notification":true},"package_pickup":{"enabled":false,"mode":"none","record":null,"notification":false}},"threshold":{"loitering":10,"package_delivery":2},"triggers":[]},"concierge_settings":{"mode":"disabled"},"sheila_settings":{"cv_processing_enabled":false,"local_storage_enabled":false},"server_settings":{"ring_media_server_enabled":true,"ring_media_server_host":"rms-eu-west-1.rapi.us-east-1.prod.client.cap.ring.devices.a2z.com"},"cv_paid_features":{"baby_cry":true,"car_alarm":true,"co2_smoke_alarm":true,"dog_bark":true,"general_sound":true,"glass_break":true,"human":true,"loitering":true,"motion":true,"other_motion":true,"package_delivery":true,"package_pickup":true,"cv_triggers":true},"other_paid_features":{"alexa_concierge":true,"sheila_cv":true,"sheila_recording":true},"zone_settings":{"motion":[{"name":"Default Zone","state":"enabled","properties":{"detection_types":["motion"],"style":1},"vertices":[{"x":0.018799,"y":0.583241},{"x":0.148606,"y":0.568924},{"x":0.546306,"y":0.648684},{"x":0.978516,"y":0.593712},{"x":1,"y":0.980629},{"x":0.666666,"y":0.980629},{"x":0.333333,"y":0.980629},{"x":0,"y":0.980629}]},{"name":"Pakketzone","state":"enabled","properties":{"detection_types":["package_delivery"],"style":4},"vertices":[{"x":0.132819,"y":0.618186},{"x":0.338057,"y":0.742931},{"x":0.46835,"y":0.782197},{"x":0.756836,"y":0.824604},{"x":0.872997,"y":0.927858},{"x":0.548672,"y":0.976707},{"x":0.209639,"y":0.972776},{"x":0.035645,"y":0.717547}]}]},"stark_enrolled":false,"network_settings":{"mac_address_ble":null,"max_dynamic_listen_interval":null,"network_diagnosis":{"channel_analysis":null,"periodic_diagnosis":null,"lan_performance":null,"tcp_iperf":null,"tcp_host":null,"tcp_port":null,"udp_iperf":null,"udp_host":null,"udp_port":null,"udp_bandwidth":null},"multi_net_pref":3,"mac_address_wifi_24":null,"mac_address_wifi_5":null},"motion_zones":[1,1,1,1,1],"enable_vod":1,"exposure_control":2,"vod_suspended":0,"vod_status":"enabled","voice_volume":5,"video_settings":{"encryption_enabled":false,"encryption_method":1,"hevc_enabled":false},"advanced_motion_zones":{"zone1":{"name":"Default Zone","state":2,"vertex1":{"x":0.018799,"y":0.583241},"vertex2":{"x":0.148606,"y":0.568924},"vertex3":{"x":0.546306,"y":0.648684},"vertex4":{"x":0.978516,"y":0.593712},"vertex5":{"x":1,"y":0.980629},"vertex6":{"x":0.666666,"y":0.980629},"vertex7":{"x":0.333333,"y":0.980629},"vertex8":{"x":0,"y":0.980629}},"zone2":{"name":"Zone 2","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0},"vertex3":{"x":0,"y":0},"vertex4":{"x":0,"y":0},"vertex5":{"x":0,"y":0},"vertex6":{"x":0,"y":0},"vertex7":{"x":0,"y":0},"vertex8":{"x":0,"y":0}},"zone3":{"name":"Zone 3","state":0,"vertex1":{"x":0,"y":0},"vertex2":{"x":0,"y":0},"vertex3":{"x":0,"y":0},"vertex4":{"x":0,"y":0},"vertex5":{"x":0,"y":0},"vertex6":{"x":0,"y":0},"vertex7":{"x":0,"y":0},"vertex8":{"x":0,"y":0}}},"advanced_motion_zones_enabled":true,"advanced_motion_zones_type":"8vertices","advanced_pir_motion_zones":{"zone1_sensitivity":5,"zone2_sensitivity":5,"zone3_sensitivity":5,"zone4_sensitivity":5,"zone5_sensitivity":5,"zone6_sensitivity":5},"pir_sensitivity_1":0,"lite_24x7":{"subscribed":true,"enabled":true,"frequency_secs":300,"resolution_p":360},"rich_notifica-uuid":false},"features":{"cfes_eligible":true,"motion_zone_recommendation":false,"motions_enabled":true,"show_recordings":true,"show_vod_settings":true,"rich_notifications_eligible":true,"show_offline_motion_events":false,"sheila_camera_eligible":true,"sheila_camera_processing_eligible":true,"dynamic_network_switching_eligible":false,"chime_auto_detect_capable":true,"show_24x7_lite":true},"ext_power_state":3}],"chimes":[],"intercoms":[],"devices":[]}],"amazonKeyLocks":[]}
Yes I do get notifications on my ring app (and alexa echo)
What kind of screenshot do you want from Ring? From the history of events or from the notification in the notificationbar?
from ring.
Notification bar itself would be useful. Events in history don't always produce a notificaiton so it's hard to know anything from that. But I'd like to just see a notification on the phone that wasn't received at all by ring-client-api to see if there's any possible clues about why such a notification would not arrive to ring-client-api.
The problem we have here is that the overall code path isn't rocket science, rather it is quite basic. When started, ring-client-api registers as a device that can receive Firebase push notifications using a token. That token is sent to Ring via the API so that Ring services can send notifications to the token ID associated with that specific client. The client is either subscribed to events or not. If you are receiving some notifications, but not others, then it can only be that Ring is not sending notifications for that device, or perhaps it is sending a different notification type, but no idea why.
from ring.
There is some interesting information in the discovery data. For the older cameras the detection mode for motion/human/package_delivery is "cloud", while for the newer camera it is "edge". This makes me think that Ring has implemented such detection in the camera itself, which is fine, but I wonder if this type of detection actually produces a different notification message type.
Out of curiosity, do you definitely not get notifications of doorbell dings on the new doorbell? Or is there any chance that it's only motion events that are being missed?
from ring.
See attached a screenshot from my phone:
While trying to reproduce the issue, now I don't get any notification via the ring-api. It looks like it is able to connect to Ring, but while listing it doesn't get any notification. Any clue how to debug?
I'm running this example: https://github.com/dgreif/ring-client-example/blob/main/example.ts
from ring.
@danielvand Out of curiosity, did you delete and re-create the motion zone on the camera that is no longer working? I recently did this on all of my devices (Stick Up Cams, and Video Doorbell Pro) and have not been able to get motion events through ring-mqtt since. Came here looking for info on how to debug and can't even get the Data Discovery node packages to work.
from ring.
@qreeves I think it is unlikely that deleting and recreating motion zones are the cause of your issue, although I know it might seem that way if they happened at a similar time. As long as you are receiving notification on the Ring app, then notifications should work here as the methods used are identical and are completely unaware of any motion zone settings. It's based 100% on whether Ring sends a notification to the correct FCM token for the associated device or not.
If you are having issues with ring-mqtt I would suggest opening an issue on that project, but first make sure you have followed the steps outlined in the ring-mqtt v5.3.0 release notes to reset notifications. If you've done that, feel free to open an issue on the ring-mqtt project and we can look into it.
@danielvand I think I have an idea of what is happening in your case, at least why camera notifications stopped completely. I'm guessing (although I don't know this) that you generated a refresh token via the command line and are just re-using that token rather than monitoring for onRefreshTokenUpdate and saving the updated token when it arrives.
This is more critical now than in the past because the initially generated token contains just the refresh token needed to make the very first connection to the Ring API, however, during that initial connection the session is established, system ID is generated, and device registration with GCM is preformed and FCM token is generated and pushed to Ring to send the notifications. All of this is then re-encoded into the updated token so that the same GCM registration/FCM token will be used in the future.
However, if you don't save this updated refresh token, and just keep using the cli generated token over and over, ring-client-api will generate a new GCM registration/FCM token every type you reconnect. This will keep notificaitons from working during future restarts.
Can you verify if you are re-using the initial token or if you are monitoring onRefreshTokenUpdate and saving a new token?
from ring.
Yeah sorry, didn't mean to hijack here. As a FOSS dev myself, I hate opening issues until I've exhausted my ability to collect information. I will follow the correct procedure if I don't end up figuring it out. Thanks for the pointers.
from ring.
@qreeves Sure, it's no problem, just like to avoid confusion. I'm the maintainer for ring-mqtt but also spent a ton of time tracking down the notifications issues when Ring changes the behavior back a few months ago. A lot of users that either don't upgrade regularly, or don't restart often only recently started having notificaitons issues due to Ring huge outage about a week ago that forced restarts. If users had never followed the steps required in v5.3.0 and later, then they will lose notifications after that restart, even if they had continues to work up until that point.
There's also still the possibility that there are corner cases or some other behavior we haven't uncovered yet, but, so far, no user that has followed the instructions after upgrading to v5.3.0 or later have reported having the problem come back, and it's been months.
from ring.
@tsightler thanks for you answer and help! I'm following this example: https://github.com/dgreif/ring-client-example/blob/main/example.ts
This used to work in the past nicely. (Using this example I build some custom stuff, but I thought I start here again till it works) So I generate a token the first time from cli, I save that in .env file and as soon as I start it, it gets a onRefreshTokenUpdated and rewrites a new token into the .env file. But the actual token I get on the event is the same as I already got via the cli. I don't get a onRefreshTokenUpdated event (or any notifications or events) since then.
Just a thought, if it was something with the token shouldn't it work in the beginning till it expires? Also without a valid token from the beginning it shouldn’t be able to connect and/or show me the devices?
from ring.
It's getting more strange by the minute. While playing around, I see the following behaviour:
- create token via cli --> new token of 1117 chars
- run script, gets Refresh Token Updated --> same 1117 chars token as via the cli
- within seconds 2nd Refresh Token Updated --> token of 2265 chars long, which has been identical for the last days (weeks?)
So my thinking was, what if I take the Refresh Token Updated out on purpose, because with that cli generated token I can connect to the api, but no luck, same result.
I'm not sure if it's around the update of the token?
from ring.
@danielvand I tried to explain above why this is critical now when it perhaps wasn't in the past, but I guess it was not clear.
Just a thought, if it was something with the token shouldn't it work in the beginning till it expires? Also without a valid token from the beginning it shouldn’t be able to connect and/or show me the devices?
No, because again, as of a few months ago, the refresh token now contains more than just the refresh token. If you just keep using the CLI generated refresh token over and over you will never save the persistent hardware ID, GCM credentials and FCM token, as those are not generated until the first time the token is used, but after that point are stored along with the refresh token in the encoded string. It is now absolutely critical that the updated refresh token be saved and used for future restarts or notifiations will abolutely not work.
from ring.
It's getting more strange by the minute. While playing around, I see the following behaviour:
- create token via cli --> new token of 1117 chars
- run script, gets Refresh Token Updated --> same 1117 chars token as via the cli
- within seconds 2nd Refresh Token Updated --> token of 2265 chars long, which has been identical for the last days (weeks?)
Not strange, looks exactly as expected, the second updated token includes the additional persistent credentials which are used to receive push notifications, generated specifically for that registered client. In previous versions this was just generated new each time the connection to the Ring API was made, but Ring stopped allowing this some months ago, so now you must save this information, and it's now wrapped into the token.
This is why saving the refresh token is critical every single time. If you don't save that initial longer refresh token, notifications will not work on subsequent restarts of the API. If you save it at some later point, without first removing the registered device from Ring Control Center, it also will not work.
from ring.
Awesome! Glad it is working for you now!
I certainly think that there is some room for improvement here, perhaps we should generate the full credential during initial token generation via the CLI, then it would be somewhat less of an issue, but, in general, it was already important to store the tokens and most project did monitor onRefreshTokenUpdated anyway, so it was a way to address this new Ring API change without requiring a new method to be implemented for every project using this library. It just became pretty much non-optional to store them with 11.8.0 and newer since, if you don't, camera notifications will only work the very first time you use the token.
from ring.
Related Issues (20)
- API no longer returning cameras or devices HOT 1
- Intercom - Ding event not available in ioBroker where I use your adapter HOT 1
- Ring Intercom - silence Ringtone when Delay Switch is triggered
- Ring panic buttons dont show up in Home HOT 2
- Stream instantly closes after it opens HOT 9
- Intercom: It is not possible to disable HomeKit notifications when doorbell rings HOT 4
- Plugin doesn’t respect Ring app settings for Live View HOT 1
- rpc command unlock_door for ring HOT 1
- ring plugin stopped working, cant lovin anymore HOT 3
- Live stream fails/times out, snapshots work HOT 3
- Error 500 in Ring API on Homebridge HOT 49
- No longer working (cannot arm and disarm) HOT 1
- Add Medical Alert Option for Ring Alarm Integration with Home Assistant HOT 1
- Invalid discord link HOT 2
- Add ability to view camera activity in recent events HOT 1
- Ring Intercom - Possibility do make it a switch / button instead of a lock HOT 1
- No Accessories installing HOT 1
- Homebridge-Ring logs don't show up in Homebridge UI (Homebridge-Config-UI-X) HOT 1
- Add support for water valves HOT 4
- Homebridge 2 support HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ring.