{"id":34879162,"url":"https://github.com/miniontoby/pyrokid_cxr_clientm","last_synced_at":"2026-01-21T00:02:04.208Z","repository":{"id":330198547,"uuid":"1118239528","full_name":"Miniontoby/pyrokid_cxr_clientm","owner":"Miniontoby","description":"com.rokid.cxr.client-m library for Python","archived":false,"fork":false,"pushed_at":"2026-01-10T16:05:31.000Z","size":72,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-11T04:54:14.004Z","etag":null,"topics":["client-m","cxr","cxr-m","java","python","rokid","rokidglasses"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/pyrokid-cxr-clientm","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Miniontoby.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-17T13:12:50.000Z","updated_at":"2026-01-10T19:38:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Miniontoby/pyrokid_cxr_clientm","commit_stats":null,"previous_names":["miniontoby/pyrokid_cxr_clientm"],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/Miniontoby/pyrokid_cxr_clientm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Miniontoby%2Fpyrokid_cxr_clientm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Miniontoby%2Fpyrokid_cxr_clientm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Miniontoby%2Fpyrokid_cxr_clientm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Miniontoby%2Fpyrokid_cxr_clientm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Miniontoby","download_url":"https://codeload.github.com/Miniontoby/pyrokid_cxr_clientm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Miniontoby%2Fpyrokid_cxr_clientm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28618861,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T23:49:58.628Z","status":"ssl_error","status_checked_at":"2026-01-20T23:47:29.996Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-m","cxr","cxr-m","java","python","rokid","rokidglasses"],"created_at":"2025-12-26T01:40:36.641Z","updated_at":"2026-01-21T00:02:04.202Z","avatar_url":"https://github.com/Miniontoby.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# com.rokid.cxr.client-m library for Python\n\nA python port of the com.rokid.cxr.client-m Java library.\n\nThe idea is to allow you to use the CXR-M SDK on any device with bluetooth.\n\nLibrary supports Python 3.7+ (confirmed using `vermin`), for as far as Bleak supports.\n\n\n**This repo is NOT an official Rokid Glasses repo. We're not associated with Rokid.**\n*This is just a personal project to port CXR-M to python, so it can be used on any platform, instead of only phones with android 10+*\n\n\n## Info\n\nThe Rokid Glasses do have to be re-paired in order for this to connect.\n\nGuide below should help you. If you were to run into issues after you done all the steps according to your display,\nthen you could make an issue if there isn't one for your display yet.\n\n\n## Current Status\n\nCurrently as of v0.0.4a4, only the libcaps.so library is ported.\nOther than that, also the `utils.LogUtil`, `utils.ValueUtil`, `extend.callbacks`, `extend.infos`, `extend.listeners`, `extend.version` and `extend.sync` have all been ported.\nAlso `extend.controllers.FileController` is finished and working. You just need to have wifi already enabled for you to use it already,\nsince I'm still working making the bluetooth connection more stable.\nThe WifiController is coming soon, tho.\n\nI also added `customview` to the library which does NOT exist in the java SDK, but does allow you to make sure your CustomViews are valid JSON.\n\nI already have more code, which connects to the glasses and actually is able to send stuff to the glasses,\nbut it's still not fully perfect. I'm still decompiling java and c code and still developing the rest.\nConsider giving me my time to work it out. Anyways, as always God bless and peace out!\n\n\n## Setting up\n\nInstall this library using `pip install pyrokid-cxr-clientm`\n\n### Dependencies\n\nWhen running the install command, python will automatically install the requirements.\nBut that doesn't stop me being transparent about the dependencies, so here's the list and why its used:\n\n- Bleak: The main Bluetooth library, supports all platforms and is easy to work with, so that's why I'm using it.\n- pybluez: Secondary Bluetooth library, used when you're running on python \u003c3.9, for the Rfcomm socket, which is built-in starting from python 3.9+\n- tzlocal: A library which allows me to get your machine's timezone name (like `Europe/Amsterdam`) to send with the `setGlassTime()` method\n- pycryptodome: A library for doing AES hashing, needed to do `CxrApi.checkGlassesSn()`, which will check if the clientSecret and license file are correct. *(altho this part is also edited to continue regardless of it being correct)*\n- requests: A library for performing a POST HTTP request for the `extend.version.check_util.CheckUtil` class. I could've used httplib, but requests is much easier to work with.\n- dataclasses_json: A library to make it easier to encode and decode dataclasses to and from JSON strings.\n- faster-whisper: For doing Speech to text\n- numpy: For doing stuff with arrays and shit. Mostly related to the speech to text.\n- soundfile: For doing stuff with ogg files\n- scipy: For resampling ogg files from 48k to 16k\n\nYou can safely ignore the huggingface warning.\n\n\n## API/Example\n\nHere is an example code with comments to explain the API functions:\n\n```py\n# Imports\nfrom pyrokid_cxr_clientm import Caps\nfrom pyrokid_cxr_clientm.utils import ValueUtil\nfrom pyrokid_cxr_clientm.extend.callbacks import *\nfrom pyrokid_cxr_clientm.extend.infos import *\nfrom pyrokid_cxr_clientm.extend.listeners import *\n\n# Decode bytes to a Caps object\nbytes_variable = b'\\x00\\x00\\x00\\x99\\x05\\x05SSSuu$xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\\x11MA:C0:AD:DR:ES:SSTxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==\\x01\\x01'\ncaps = Caps.fromBytes(bytes_variable)\nprint(caps)\nprint('socketUuid:', caps.at(0).getString())\nprint('macAddress:', caps.at(1).getString())\nprint('rokidAccount:', caps.at(2).getString())\nprint('glassesType:', caps.at(3).getUInt32()) # 0-no display, 1-have display\n\n# Encode Caps object to bytes\ncaps = Caps()\ncaps.writeUInt32(0x1004)\ncaps.writeUInt32(1)\ncaps.writeUInt32(5)\ncaps.write('TestDevice')\ncaps.writeUInt64(1765983621057)\ndata = caps.serialize()\nprint(data)\n```\n\n----\n\nTo download files from your device, when the glasses are already connected to wifi (since I've not added the bluetooth controller yet), you can use this snippet:\n```py\nfrom pyrokid_cxr_clientm.utils import ValueUtil\nfrom pyrokid_cxr_clientm.extend.controllers import FileController, WifiController\nimport os, logging\n\nlogging.basicConfig(level=logging.INFO)\n\nsavePath = 'media/'\nos.makedirs(savePath, exist_ok=True) # Make the folder if it doesnt exist yet\ntypes = [ValueUtil.CxrMediaType.PICTURE] # Select the type of media you want to download, you can do [ValueUtil.CxrMediaType.ALL] if you want all media types\n\nclass fileCallback(FileController.Callback):\n\tdef onDownloadStart(self) -\u003e None:\n\t\tprint('Download Start')\n\tdef onSingleFileDownloaded(self, fileName: str) -\u003e None:\n\t\tprint('Single File Downloaded', fileName)\n\tdef onDownloadFailed(self) -\u003e None:\n\t\tprint('Download Failed!')\n\tdef onDownloadFinished(self) -\u003e None:\n\t\tprint('Download Finished!')\n\t\tquit()\n\nclass wifiCallback(WifiController.Callback):\n\tdef onStatusUpdate(self, cxrStatus: ValueUtil.CxrStatus, cxrWifiErrorCode: ValueUtil.CxrWifiErrorCode) -\u003e None: pass\n\tdef onAddress(self, address: str) -\u003e None:\n\t\tFileController.getInstance().startDownload(0, savePath, types, None, address, fileCallback())\n\t\t# Now just wait, it is still running in the background!\n\t\tFileController.getInstance().i.t.join()\n\nWifiController.getInstance().init(0, \"\", wifiCallback())\n```\n\n*P.s. when downloading VIDEO files, you will also see .txt files show up. Those are used by the Hi Rokid app to do the post stabilisation*\n\n----\n\nTo upload apk's to the glasses to sideload the apk, you can use this snippet to wirelessly (without dev cable) do that. (Again wifi needs to be ON for this to work)\n\n```py\nfrom pyrokid_cxr_clientm.utils import ValueUtil\nfrom pyrokid_cxr_clientm.extend.callbacks import ApkStatusCallback\nfrom pyrokid_cxr_clientm.extend.controllers import FileController, WifiController\nimport os, logging\n\nlogging.basicConfig(level=logging.INFO)\napkPath = 'org.fdroid.fdroid_1023050.apk' # path to the .apk on your computer\n\nclass apkStatusCallback(ApkStatusCallback):\n\tdef onUploadApkSucceed(self) -\u003e None:\n\t\tprint('Upload Apk Succeed')\n\t\tquit()\n\tdef onUploadApkFailed(self) -\u003e None:\n\t\tprint('Upload Apk Failed')\n\tdef onInstallApkSucceed(self) -\u003e None: pass # These ones won't trigger, cause you're not using Bluetooth!\n\tdef onInstallApkFailed(self) -\u003e None: pass\n\tdef onUninstallApkSucceed(self) -\u003e None: pass\n\tdef onUninstallApkFailed(self) -\u003e None: pass\n\tdef onOpenAppSucceed(self) -\u003e None: pass\n\tdef onOpenAppFailed(self) -\u003e None: pass\n\nclass wifiCallback(WifiController.Callback):\n\tdef onStatusUpdate(self, cxrStatus: ValueUtil.CxrStatus, cxrWifiErrorCode: ValueUtil.CxrWifiErrorCode) -\u003e None: pass\n\tdef onAddress(self, address: str) -\u003e None:\n\t\tFileController.getInstance().startUploadApk(apkPath, address, apkStatusCallback())\n\t\t# Now just wait, it is still running in the background!\n\n\t\t# You could do this to kinda let the thing still wait. Should be fine\n\t\tFileController.getInstance().r.t.join()\n\nWifiController.getInstance().init(0, \"\", wifiCallback())\n```\n\nIf everything went right, you should now see a new app at the very end of the apps screen.\n\n\n## Extra API Documentation\n\nExtra API documentation can be found on the [ReadTheDocs](https://pyrokid-cxr-clientm.readthedocs.io/en/latest/) documentation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminiontoby%2Fpyrokid_cxr_clientm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminiontoby%2Fpyrokid_cxr_clientm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminiontoby%2Fpyrokid_cxr_clientm/lists"}