Giter Club home page Giter Club logo

Comments (15)

danielvand avatar danielvand commented on September 21, 2024 1

@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.

tsightler avatar tsightler commented on September 21, 2024

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.

danielvand avatar danielvand commented on September 21, 2024

{"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.

tsightler avatar tsightler commented on September 21, 2024

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.

tsightler avatar tsightler commented on September 21, 2024

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.

danielvand avatar danielvand commented on September 21, 2024

See attached a screenshot from my phone:
Screenshot
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?
image
I'm running this example: https://github.com/dgreif/ring-client-example/blob/main/example.ts

from ring.

qreeves avatar qreeves commented on September 21, 2024

@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.

tsightler avatar tsightler commented on September 21, 2024

@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.

qreeves avatar qreeves commented on September 21, 2024

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.

tsightler avatar tsightler commented on September 21, 2024

@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.

danielvand avatar danielvand commented on September 21, 2024

@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.

danielvand avatar danielvand commented on September 21, 2024

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.

tsightler avatar tsightler commented on September 21, 2024

@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.

tsightler avatar tsightler commented on September 21, 2024

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.

tsightler avatar tsightler commented on September 21, 2024

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)

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.