cybear-jinni / cbj_hub Goto Github PK
View Code? Open in Web Editor NEWπΈοΈ Easy to use open source Hub to control your smart devices from one app.
Home Page: https://cybearjinni.com
License: GNU Affero General Public License v3.0
πΈοΈ Easy to use open source Hub to control your smart devices from one app.
Home Page: https://cybearjinni.com
License: GNU Affero General Public License v3.0
We need to implement at last one example of how our code need to handle discovering new devices in the network.
git action for ci has been removed accidentally a long time ago and we need to bring it back.
Currently we are using print to log our Info Warnings and Errors.
Let's find a better way to do so
Follow up to #59 we now need to convert all the pints in the app to use the new log system that we have added.
Just use logger.i('Text');
instead of print('Text');
and import the logger function from
import package:cbj_hub/utils.dart';
Here are the types of log that you can use
logger.v("Verbose log");
logger.d("Debug log");
logger.i("Info log");
logger.w("Warning log");
logger.e("Error log");
logger.wtf("What a terrible failure log");
Since Remote Pips is in a working state (each home needs to be configured manually) we need to add support for adding your home path DNS inside the app so that it will know where it should connect to.
The DNS will get sent from the App, we need to save it locally and start the connection to it whenever the device boots up.
Currently there is no support for a smart plug generic type.
Currently all devices get added automatically without rooms but get categorized to room name Discovered.
The Hub should support rooms and have a list of devices that exist in this room, it should also send a rooms list to the app so that it can show the user the devices in a room configuration.
Snap crash when started with device
Log:
user:~$ sudo snap logs cbj-hub -n 50
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β 00:09:21.066 (+0:00:00.319403)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β π‘ Scenes got saved to local storage
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β 00:09:21.103 (+0:00:00.356716)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β π‘ Devices got saved to local storage
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β 00:09:21.117 (+0:00:00.370342)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β π‘ Devices got saved to local storage
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β 00:09:21.128 (+0:00:00.381325)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: β π‘ Devices got saved to local storage
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: Unhandled exception:
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: SocketException: OS Error: Connection refused, errno = 111, address = localhost, port = 55164
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #0 _NativeSocket.startConnect (dart:io-patch/socket_patch.dart:681)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #1 _RawSocket.startConnect (dart:io-patch/socket_patch.dart:1808)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #2 RawSocket.startConnect (dart:io-patch/socket_patch.dart:27)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #3 Socket._startConnect (dart:io-patch/socket_patch.dart:2027)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #4 Socket.startConnect (dart:io/socket.dart:784)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #5 _ConnectionTarget.connect (dart:_http/http_impl.dart:2439)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #6 _HttpClient._getConnection.connect (dart:_http/http_impl.dart:2808)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #7 _HttpClient._getConnection (dart:_http/http_impl.dart:2813)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #8 _HttpClient._openUrl (dart:_http/http_impl.dart:2697)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #9 _HttpClient.openUrl (dart:_http/http_impl.dart:2569)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #10 IOClient.send (package:http/src/io_client.dart:35)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #11 BaseClient._sendUnstreamed (package:http/src/base_client.dart:93)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #12 BaseClient.post (package:http/src/base_client.dart:32)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #13 post.<anonymous closure> (package:http/http.dart:69)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #14 _withClient (package:http/http.dart:164)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #15 post (package:http/http.dart:68)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #16 NodeRedAPI.postFlow (package:cbj_hub/infrastructure/node_red/node_red_api/node_red_api.dart:142)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #17 NodeRedRepository.createNewNodeRedScene (package:cbj_hub/infrastructure/node_red/node_red_repository.dart:25)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: #18 SceneCbjRepository.addNewScene (package:cbj_hub/infrastructure/scenes/scene_repository.dart:72)
2022-06-02T00:09:21+03:00 cbj-hub.cbj-hub[2229]: <asynchronous suspension>
2022-06-02T00:09:21+03:00 systemd[1]: snap.cbj-hub.cbj-hub.service: Main process exited, code=exited, status=255/EXCEPTION
2022-06-02T00:09:21+03:00 systemd[1]: snap.cbj-hub.cbj-hub.service: Failed with result 'exit-code'.
2022-06-02T00:09:21+03:00 systemd[1]: snap.cbj-hub.cbj-hub.service: Scheduled restart job, restart counter is at 11.
2022-06-02T00:09:21+03:00 systemd[1]: Stopped Service for snap application cbj-hub.cbj-hub.
2022-06-02T00:09:21+03:00 systemd[1]: snap.cbj-hub.cbj-hub.service: Start request repeated too quickly.
2022-06-02T00:09:21+03:00 systemd[1]: snap.cbj-hub.cbj-hub.service: Failed with result 'exit-code'.
2022-06-02T00:09:21+03:00 systemd[1]: Failed to start Service for snap application cbj-hub.cbj-hub.
After 10m the connection to the remote pipes time out with the error
β Client stream error: gRPC Error (code: 2, codeName: UNKNOWN, message: HTTP/2 error: Connection error: Connection is being forcefully terminated. (errorCode: 10), details: null, rawResponse: null, trailers: {})
Currently smart plugs and touch switches are the same for the hub.
Tuya API response includes both devType
and haType
but they are both switch types which I think is a bug in their API.
The only differentiate that I have found in the response of the device is the attached image URL of the device but this is not a good way to distinguish between the devices.
ESPHome is a system to control your ESP8266/ESP32 by simple yet powerful configuration files and control them remotely through Home Automation systems.
I think ESPHome is owned by Home Assistant.
Percent of users in Home Assistant is 17.5
Unhandled exception:
SocketException: Send failed (OS Error: Network is unreachable, errno = 101), address = 0.0.0.0, port = 5353
#0 _NativeSocket.send (dart:io-patch/socket_patch.dart:1213:34)
#1 _RawDatagramSocket.send (dart:io-patch/socket_patch.dart:2450:15)
#2 MDnsClient.lookup (package:multicast_dns/multicast_dns.dart:225:14)
#3 MdnsScanner._findingMdnsWithAddress (package:network_tools/src/mdns_scanner/mdns_scanner.dart:71:54)
<asynchronous suspension>
#4 MdnsScanner.searchMdnsDevices (package:network_tools/src/mdns_scanner/mdns_scanner.dart:41:29)
<asynchronous suspension>
#5 CompaniesConnectorConjector.searchAllMdnsDevicesAndSetThemUp (package:cbj_hub/infrastructure/devices/companies_connector_conjector.dart:144:43)
<asynchronous suspension>
As you can see the git action format did a format on lib/injection.config.dart
b66e3c1
injection.config.dart
is autogenerated file and thus should not get formatted.
Please change git action dart format so that it will ignore lib/injection.config.dart
cbj_hub/.github/workflows/format.yml
Line 29 in 4e84eca
Should become
find . -name "*.dart" ! -path '*/gen/*' ! -name 'injection.config.dart' | tr '\n' ' ' | xargs dart format
Tuya has a lot of companies that have +- the same API as I wrote in old Tuya support issue #7
- SmartThings
- Smart Homy
- Lloyd
- Baiyu Electronics
- Calex
And the list go on.
Adding support for them doesn't suppose to be difficult.
I think most of this list is wrong and the companies don't need to be on this list like Samsung SmartThings.
Other big companies that do have Tuya API are missing like Smart Life
.
So here is my current list:
Tuya, Smart Life, Jinvoo Smart are all combined in Home Assistant with 0.74% of the users.
Switcher creates smart devices and most famously known for their Boiler products.
Percent of users in Home Assistant lass than 1%.
As will be explained in the TODO here
//TODO: We need to write to mqtt massage that will make all the tasmota
// devices repost in discovery. Currently we recognize only the tasmota
// devices that coming online after the program got turned on.
Currently our device entity are being used as one entity for each company.
This is bad practice and should be changed to work by device type.
More over each company device implementation will be converted to the hub devices types.
This change will benefit us in several ways:
Mycfort is a private and open Voice Assistant
It will be nice to be able to control your smart home by voice.
Mycroft supports skills that can be created and uploaded to the skills store.
Let's create a skill to control CyBear Jinni Hub by voice through Mycroft.
We need to find a way to run dart format .
on incoming pull requests and commit it automatically without the intervention of the commiter.
Philips Hue devices are very popular.
In Home Assistant 14.9% of its users use it.
And is the fourth most used plugin in homebridge.
So adding support for it takes priority.
Whenever I exist the app the hub crash with GRPc error code status 1.
This is because too things.
For now fixing 2 is enough.
As we add support for switcher V2 (boiler) we now move forward to blinds.
I have found two repos that support blinds
switcher-js and homebridge-switcher-platform.
Let's continue and add support for it too
One way to simplify creation of scenes for the user is by creating predefined scenes for each area depending on the area layble.
For example area with a sleeping room label will have scene named sleep which will close all lights in the room.
This way the user will not have to create "generic scenes".
The scenes that will get created will also have thinking behind them and sometimes even support by since which will help the user automatically to enhance his life and achieve his goals without even knowing that.
For example for studying and working all colored changing light bulbs will change to white/blue color as it enhances concentrations by around 13%.
Unhandled exception:
Bad state: Stream has already been listened to.
#0 _StreamController._subscribe (dart:async/stream_controller.dart:676:7)
#1 _ControllerStream._createSubscription (dart:async/stream_controller.dart:827:19)
#2 _StreamImpl.listen (dart:async/stream_impl.dart:473:9)
#3 _StreamIterator._initializeOrDone (dart:async/stream_impl.dart:1028:33)
#4 _StreamIterator.moveNext (dart:async/stream_impl.dart:1004:12)
#5 CompaniesConnectorConjector.searchPingableDevicesAndSetThemUpByHostName (package:cbj_hub/infrastructure/devices/companies_connector_conjector.dart)
<asynchronous suspension>
Shelly is a big player in the smart home system.
In Home Assistant 12.7% of its users use it.
Shelly suppose to have cloud API so it does not need to be so hard to add support for it, but local control is preferred if exists any.
LIFX is a big company in the smart home ecosystem.
In Home Assistant 0.43% of its users use it.
βYeelight is one of the lower price points smart devices company.
I think it is owned by Xiaomi.
Percent of users in Home Assistant is 5.7%.
We need to catch this exception before it crashes the Hub.
To reproduce you will need a switcher boiler (I used V2).
Turn boiler on/off a couple of times using the app and you will get this error massage in the hub.
The last part of the console:
Got From App
Boiler turn on success
Unhandled exception:
SocketException: OS Error: Broken pipe, errno = 32, address = 192.168.31.206, port = 51146
The Hub should be uploaded to the snap store for easy install and getting updates.
After that we need to add link in the readme to the snap store page.
Tuya API does not return the state of touch switches using the request to
https://px1.tuya$region.com/homeassistant/skill
It does return the state of light objects but not for touch switches.
Maybe there is another API call better for switches or the data needed to be sent differently.
Please update all project dependencies to the last version.
If the project gets compiled I will probably accept the pr.
Currently we scan all the time each vendor that we support.
This is not so efficient as it is a lot of unnecessary scans as most homes do not contain all the vendors that we support.
And our vendor's support will only grow larger and with it the inefficiency of scanning all of them.
There are a number of smart devices that support mDNS protocols.
My suggestion is to scan all the mDNS devices in the network and activate specific devices vendor scan for serviceType that corresponds to this vendor.
This way we will activate only vendors that exist in the user local network.
If multiple clients try to connect the hub crash with error that stream is already listened too.
The error is on the stream from the hub to the app inside the hub that keeps sending data of changes into the actual GRPc open stream of the hub and the app.
Tasmota is
Open source firmware for ESP8266 devices
for my understanding it is quite popular among makers and tinkerers.
It is using MQTT to talk to devices.
We are using a package named mqtt_client to use the protocol, specific implementation for Tasmota is needed.
9% of Home Assistant users are using it.
As a lot of smart devices yous MQTT we can easily add support for them since we already using some form of it.
As written in it site home page
MQTT: The Standard for IoT Messaging
37.5% of Home Assistant users using it.
So adding support for it takes priority.
Hub crash whenever the network is down, on boot or while it is running
Error from the log
Unhandled exception:
SocketException: Failed host lookup: 'px1.tuyaeu.com' (OS Error: Temporary failure in name resolution, errno = -3)
#0 _NativeSocket.startConnect (dart:io-patch/socket_patch.dart:681:35)
#1 _RawSocket.startConnect (dart:io-patch/socket_patch.dart:1808:26)
#2 RawSocket.startConnect (dart:io-patch/socket_patch.dart:27:23)
#3 RawSecureSocket.startConnect (dart:io/secure_socket.dart:237:22)
#4 SecureSocket.startConnect (dart:io/secure_socket.dart:60:28)
#5 _ConnectionTarget.connect (dart:_http/http_impl.dart:2437:24)
#6 _HttpClient._getConnection.connect (dart:_http/http_impl.dart:2808:12)
#7 _HttpClient._getConnection (dart:_http/http_impl.dart:2813:12)
#8 _HttpClient._openUrl (dart:_http/http_impl.dart:2697:12)
#9 _HttpClient.openUrl (dart:_http/http_impl.dart:2569:7)
#10 IOClient.send (package:http/src/io_client.dart:35:38)
#11 BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:38)
#12 BaseClient.post (package:http/src/base_client.dart:32:7)
#13 post.<anonymous closure> (package:http/http.dart:69:16)
#14 _withClient (package:http/http.dart:164:20)
#15 post (package:http/http.dart:68:5)
#16 CloudTuya.consistentRequest (package:cbj_hub/infrastructure/devices/tuya_smart/tuya_smart_remote_api/cloudtuya.dart:178:37)
#17 CloudTuya.login (package:cbj_hub/infrastructure/devices/tuya_smart/tuya_smart_remote_api/cloudtuya.dart:63:15)
#18 TuyaSmartConnectorConjector.accountLogin (package:cbj_hub/infrastructure/devices/tuya_smart/tuya_smart_connector_conjector.dart:34:49)
#19 CompanysConnectorConjector.setVendorLoginCredentials (package:cbj_hub/infrastructure/devices/companys_connector_conjector.dart:119:12)
#20 HiveRepository.loadFromDb.<anonymous closure> (package:cbj_hub/infrastructure/local_db/local_db_repository.dart:65:34)
#21 Right.fold (package:dartz/src/either.dart:200:64)
#22 HiveRepository.loadFromDb (package:cbj_hub/infrastructure/local_db/local_db_repository.dart:64:10)
<asynchronous suspension>
Process finished with exit code 255
CyBear Jinni is intended to be as easy to install/configure as much as possible.
Our app for android can easily be download from google play.
The hub is little bit more difficult, and we want to fix that for RaspberryPi users.
Please create an iso image for RaspberryPi that contain
Our ESPHome implementation for switch on/off disconnects before request is complete.
Scenes are one button that the user can press and it will create multiple predefined actions.
For example Going out
scene will close all the lights and the blinds in the home.
Adding support for this functionality should not be to hard as we are using MQTT that act as part of the logic.
Currently we can defined and user the described functionality in a program called Node-RED
, this program talk to the MQTT broker and I think add the described logic as JavaScript.
So first we need to verify that what that I am saying is the way that it is works,
Prof of concept, find a way to send new logic from the code.
And make it accessible to client requests such as the app.
Crash from gRPC package.
Log from hub:
Unhandled exception:
Bad state: Cannot add event after closing
#0 _StreamController.add (dart:async/stream_controller.dart:595:24)
#1 _StreamSinkWrapper.add (dart:async/stream_controller.dart:867:13)
#2 TransportStream.sendHeaders (package:http2/transport.dart:147:22)
#3 ServerHandler_.sendTrailers (package:grpc/src/server/handler.dart:361:13)
#4 ServerHandler_._sendError (package:grpc/src/server/handler.dart:410:5)
#5 ServerHandler_._onResponse (package:grpc/src/server/handler.dart:287:7)
#6 _RootZone.runUnaryGuarded (dart:async/zone.dart:1618:10)
#7 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:341:11)
#8 _DelayedData.perform (dart:async/stream_impl.dart:591:14)
#9 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:706:11)
#10 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:663:7)
#11 _microtaskLoop (dart:async/schedule_microtask.dart:40:21)
#12 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5)
#13 _runPendingImmediateCallback (dart:isolate-patch/isolate_patch.dart:122:13)
#14 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:193:5)
Tried to put try catch around that line and it fixed the crash
https://github.com/grpc/grpc-dart/blob/94b71a3e1cbfae366ead2d67f1b30fd03b8d4ee2/lib/src/server/handler.dart#L361
Created issue in gRPC package and opened this repo in order to reproduce it in a clean environment.
Currently ESPHome basic implementation is located in here.
Better option will be to move the implementation out of the hub repo and just to add it as dependence.
This will make the hub code cleaner and will be easier to maintain and peoples will be able to re use it.
The client package will be similar to the one in python
Please create the dart package in your own repo and post here the pub.dev package page.
Remote Pipes do not reconnect whenever
Tuya devices are popular option when its come to smart devices.
It is one of the most used smart devices in Home Assistant with 14.4% of its users using it.
So adding support for that takes priority.
Detect Chromecast devices in your local network.
Adding support for it will require adding a new generic type generic smartTV
.
RGBW light object does not support changing color, only turning light on/off.
The Hub got built around the concept of MQTT in order to use tools like Node-RED to its advantage.
Node-RED is a programming tool for wiring together hardware devices, APIs and online services in new and interesting ways.
It provides a browser-based editor that makes it easy to wire together flows using the wide range of nodes in the palette that can be deployed to its runtime in a single-click.
Node-RED is full of features and has a pretty good graphical user interface.
Let's create an integration layer with Node-RED to control and change nodes inside of it.
Device name Χ‘ΧΧ ΧΧͺ Χ’Χ₯
after transferred to MQTT and back will become Γ‘οΏ½ΓοΏ½Γ οΏ½ΓοΏ½ΓͺοΏ½ Γ’οΏ½Γ₯οΏ½
.
Following #48 the only basic function left for switcher devices is stoping the blinds.
An example for implementation for stoping the blinds can be found homebridge-switcher-platform.
Also switcher API is missing a way to get the position of the blinds, please add it as well.
While running the hub I am getting an error in the console
β β Error discover in Yeelight
β β Null check operator used on a null value
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.