Metadata-Version: 2.4
Name: pyrokid_cxr_clientm
Version: 0.0.4a5
Summary: A python port of the com.rokid.cxr.client-m Java library.
Author-email: Miniontoby <author@example.com>
License-Expression: GPL-3.0
Project-URL: Homepage, https://github.com/Miniontoby/pyrokid_cxr_clientm
Project-URL: Documentation, https://pyrokid-cxr-clientm.readthedocs.io/en/latest/
Project-URL: Repository, https://github.com/Miniontoby/pyrokid_cxr_clientm.git
Project-URL: Bug Tracker, https://github.com/Miniontoby/pyrokid_cxr_clientm/issues
Keywords: rokid,cxr,client-m,glasses,rokid glasses,com.rokid.cxr.client-m
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Communications
Classifier: Topic :: Multimedia :: Sound/Audio :: Capture/Recording
Classifier: Topic :: Multimedia :: Sound/Audio :: Sound Synthesis
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
Classifier: Topic :: Multimedia :: Video :: Capture
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Interface Engine/Protocol Translator
Classifier: Topic :: Software Development :: Libraries :: Java Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: bleak
Requires-Dist: pybluez; python_version < "3.9"
Requires-Dist: tzlocal
Requires-Dist: pycryptodome
Requires-Dist: requests
Requires-Dist: dataclasses_json
Requires-Dist: faster-whisper
Requires-Dist: numpy
Requires-Dist: soundfile
Requires-Dist: scipy
Dynamic: license-file

# com.rokid.cxr.client-m library for Python

A python port of the com.rokid.cxr.client-m Java library.

The idea is to allow you to use the CXR-M SDK on any device with bluetooth.

Library supports Python 3.7+ (confirmed using `vermin`), for as far as Bleak supports.


**This repo is NOT an official Rokid Glasses repo. We're not associated with Rokid.**
*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+*


## Info

The Rokid Glasses do have to be re-paired in order for this to connect.

Guide below should help you. If you were to run into issues after you completed all the steps,
then you could make an issue if there isn't one yet for the problem you are facing.
Opening issues of stuff that has already been answered will be closed without response.


## Current Status

Currently as of v0.0.4a5, only the libcaps.so library is ported.

Other than that, also the `utils.LogUtil`, `utils.ValueUtil`, `extend.callbacks`, `extend.infos`, `extend.listeners`, `extend.version` and `extend.sync` have all been ported.
Also `extend.controllers.FileController` is finished and working. You just need to have wifi already enabled for you to use it already,
since I'm still working making the bluetooth connection more stable.

Also the `extend.controllers.WifiController` is 'finished'. It does a port scan on your network to find the glasses its webserver.
The original Android/Java library uses WiFi Direct P2P, but I am, as of right now, unable to make that work crossplatform.
To add to that: I am also not even able to just do it for Windows.
And since a port scan does work on WiFi networks without a firewall blocking connections to other IP's on the network, I think this is the best for now.
The only downside is that your glasses must have been connected to the network during a firmware upgrade, else it won't try to connect.
The reason why Hi Rokid is able to connect to the glasses no matter what internet you're connected to or if you're not even connected to wifi,
is because of WiFi direct, where the glasses make a wifi 'hotspot' which the phone connects to and then talks to the glasses.

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

I already have more code, which connects to the glasses and actually is able to send stuff to the glasses,
but it's still not fully perfect. I'm still decompiling java and c code and still developing the rest.
Consider giving me my time to work it out. Anyways, as always God bless and peace out!


## Setting up

Install this library using `pip install pyrokid-cxr-clientm`

### Dependencies

When running the install command, python will automatically install the requirements.
But that doesn't stop me being transparent about the dependencies, so here's the list and why its used:

- Bleak: The main Bluetooth library, supports all platforms and is easy to work with, so that's why I'm using it.
- pybluez: Secondary Bluetooth library, used when you're running on python <3.9, for the Rfcomm socket, which is built-in starting from python 3.9+
- tzlocal: A library which allows me to get your machine's timezone name (like `Europe/Amsterdam`) to send with the `setGlassTime()` method
- 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)*
- 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.
- dataclasses_json: A library to make it easier to encode and decode dataclasses to and from JSON strings.
- faster-whisper: For doing Speech to text
- numpy: For doing stuff with arrays and shit. Mostly related to the speech to text.
- soundfile: For doing stuff with ogg files
- scipy: For resampling ogg files from 48k to 16k

If you see a warning about huggingface when running the code, you can safely ignore the warning.


## API/Example

Here is an example code with comments to explain the API functions:

```py
# Imports
from pyrokid_cxr_clientm import Caps
from pyrokid_cxr_clientm.utils import ValueUtil
from pyrokid_cxr_clientm.extend.callbacks import *
from pyrokid_cxr_clientm.extend.infos import *
from pyrokid_cxr_clientm.extend.listeners import *

# Decode bytes to a Caps object
bytes_variable = b'\x00\x00\x00\x99\x05\x05SSSuu$xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\x11MA:C0:AD:DR:E5:50Txxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==\x01\x01'
caps = Caps.fromBytes(bytes_variable)
print(caps)
print('socketUuid:', caps.at(0).getString())
print('macAddress:', caps.at(1).getString())
print('rokidAccount:', caps.at(2).getString())
print('glassesType:', caps.at(3).getUInt32()) # 0-no display, 1-have display

# Encode Caps object to bytes
caps = Caps()
caps.writeUInt32(0x1004)
caps.writeUInt32(1)
caps.writeUInt32(5)
caps.write('TestDevice')
caps.writeUInt64(1765983621057)
data = caps.serialize()
print(data)
```

----

To 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:
```py
from pyrokid_cxr_clientm.utils import ValueUtil
from pyrokid_cxr_clientm.extend.controllers import FileController, WifiController
import os, logging

logging.basicConfig(level=logging.INFO)

savePath = 'media/'
os.makedirs(savePath, exist_ok=True) # Make the folder if it doesnt exist yet
types = [ValueUtil.CxrMediaType.PICTURE] # Select the type of media you want to download, you can do [ValueUtil.CxrMediaType.ALL] if you want all media types

class fileCallback(FileController.Callback):
	def onDownloadStart(self) -> None:
		print('Download Start')
	def onSingleFileDownloaded(self, fileName: str) -> None:
		print('Single File Downloaded', fileName)
	def onDownloadFailed(self) -> None:
		print('Download Failed!')
	def onDownloadFinished(self) -> None:
		print('Download Finished!')
		quit()

class wifiCallback(WifiController.Callback):
	def onStatusUpdate(self, cxrStatus: ValueUtil.CxrStatus, cxrWifiErrorCode: ValueUtil.CxrWifiErrorCode) -> None: pass
	def onAddress(self, address: str) -> None:
		FileController.getInstance().startDownload(0, savePath, types, None, address, fileCallback())
		# Now just wait, it is still running in the background!
		FileController.getInstance().i.t.join()

WifiController.getInstance().init(0, "", wifiCallback())
```

*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*

----

To 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)

```py
from pyrokid_cxr_clientm.utils import ValueUtil
from pyrokid_cxr_clientm.extend.callbacks import ApkStatusCallback
from pyrokid_cxr_clientm.extend.controllers import FileController, WifiController
import logging

logging.basicConfig(level=logging.INFO)
apkPath = 'org.fdroid.fdroid_1023050.apk' # path to the .apk on your computer

class apkStatusCallback(ApkStatusCallback):
	def onUploadApkSucceed(self) -> None:
		print('Upload Apk Succeed')
		quit()
	def onUploadApkFailed(self) -> None:
		print('Upload Apk Failed')
	def onInstallApkSucceed(self) -> None: pass # These ones won't trigger, cause you're not using Bluetooth!
	def onInstallApkFailed(self) -> None: pass
	def onUninstallApkSucceed(self) -> None: pass
	def onUninstallApkFailed(self) -> None: pass
	def onOpenAppSucceed(self) -> None: pass
	def onOpenAppFailed(self) -> None: pass

class wifiCallback(WifiController.Callback):
	def onStatusUpdate(self, cxrStatus: ValueUtil.CxrStatus, cxrWifiErrorCode: ValueUtil.CxrWifiErrorCode) -> None: pass
	def onAddress(self, address: str) -> None:
		FileController.getInstance().startUploadApk(apkPath, address, apkStatusCallback())
		# Now just wait, it is still running in the background!

		# You could do this to kinda let the thing still wait. Should be fine
		FileController.getInstance().r.t.join()

WifiController.getInstance().init(0, "", wifiCallback())
```

If everything went right, you should now see a new app at the very end of the apps screen.


## Extra API Documentation

Extra API documentation can be found on the [ReadTheDocs](https://pyrokid-cxr-clientm.readthedocs.io/en/latest/) documentation.
