Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 35 additions & 29 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,28 +1,16 @@
Python-xsense
=============

Python-xsense is a small library to interact with the API of XSense Home
Security. It allows to retrieve the status of various devices and the
basestation.
Python-xsense is an async-only client library for X-Sense cloud accounts,
AWS IoT shadows, MQTT updates, ADDX/VicoHome camera APIs, camera history,
live-view helpers, and supported device actions/settings.

Example sync usage
------------------
This package contains reusable Python client logic only. Home Assistant
entity descriptions, icons, translations, blueprints, platform setup, and
registry cleanup belong in the Home Assistant integration.

::

>>> from xsense import XSense
>>> from xsense.utils import dump_environment
>>> api = XSense()
>>> api.init()
>>> api.login(username, password)
>>> api.load_all()
>>> for _, h in api.houses.items():
>>> for _, s in h.stations.items():
>>> api.get_state(s)
>>> dump_environment(api)

Example async usage
-------------------
Client usage
------------

::

Expand All @@ -31,18 +19,36 @@ Example async usage
>>> from xsense.utils import dump_environment
>>>
>>> async def run(username: str, password: str):
>>> api = AsyncXSense()
>>> await api.init()
>>> await api.login(username, password)
>>> for _, h in api.houses.items():
>>> for _, s in h.stations.items():
>>> await api.get_state(s)
>>> dump_environment(api)
>>> async with AsyncXSense() as api:
>>> await api.init()
>>> await api.login(username, password)
>>> await api.load_all()
>>> for house in api.houses.values():
>>> for station in house.stations.values():
>>> await api.get_state(station)
>>> dump_environment(api)
>>>
>>> asyncio.run(run(username, password))

Reusable helpers
----------------

The main async client lives in ``xsense.AsyncXSense``. It exposes the current
X-Sense app API request shape, Cognito session refresh, AWS IoT shadow
reads/writes, ADDX/VicoHome camera discovery, camera thumbnail and live-view
helpers, and supported device actions/settings.

Pure parsing helpers live in separate modules:

* ``xsense.event_parser`` parses MQTT, camera history, AI detection, presence,
and self-test event payloads.
* ``xsense.mqtt_helper`` handles X-Sense MQTT connection setup, topics,
subscription helpers, payload parsing, and publish helpers.
* ``xsense.webrtc_signal`` parses ADDX WebRTC tickets and builds/parses the
signal-server SDP and ICE payloads.

Development
-----------

This library is in an early development stage and created primarily to
make an integration for home assistant.
This library is in an early development stage. It is maintained as a
shared upstream client for integrations and other async Python consumers.
31 changes: 16 additions & 15 deletions asynctest.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import asyncio

from xsense.async_xsense import AsyncXSense
from xsense import AsyncXSense
from xsense.utils import dump_environment, get_credentials


async def run(username: str, password: str):
api = AsyncXSense()
await api.init()
await api.login(username, password)
await api.load_all()
async with AsyncXSense() as api:
await api.init()
await api.login(username, password)
await api.load_all()

for _, h in api.houses.items():
await api.get_house_state(h)
for _, s in h.stations.items():
await api.get_station_state(s)
await api.get_state(s)
for h in api.houses.values():
await api.get_house_state(h)
for s in h.stations.values():
await api.get_station_state(s)
await api.get_state(s)

if s.has_alarm:
await api.get_alarm_state(s)
if s.has_alarm:
await api.get_alarm_state(s)

dump_environment(api)
dump_environment(api)


username, password = get_credentials()
asyncio.run(run(username, password))
if __name__ == "__main__":
username, password = get_credentials()
asyncio.run(run(username, password))
10 changes: 4 additions & 6 deletions docs/protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ See below

Clienttype: 1 for IOS, 2 for Android.

App-version currently is "v1.17.2_20240115".
App-version currently is "v1.36.0_20260130".

AppCode looks like an encoded version of the App-version and is currenlty 1172 (v **1** . **17** . **2** _20240115)
AppCode looks like an encoded version of the App-version and is currently 1360 (v **1** . **36** . **0** _20260130)

The bizCode specifies which command is requested.

Expand All @@ -57,10 +57,8 @@ Some requests can be unauthenticated, other must be authenticated. Authention ca

MAC-hash
--------
All requests must include a MAC-hash. This is a md5-hash calculated over the values of all custom field included in the
request combined with the secret key.
The implementation for the hash-calculation is probably incorrect. Keys in a python-dict are unsorted which result
in hashes that are unpredictable.
All requests must include a MAC-hash. This is a md5-hash calculated over the values of all custom fields included in the
request combined with the secret key. Container values are serialized in the compact JSON form used by the Android app.

Commands
========
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["setuptools>=40.8.0", "wheel"]
build-backend = "setuptools.build_meta"
21 changes: 14 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from setuptools import setup, find_packages

VERSION = '0.0.17'
DESCRIPTION = 'XSense Python Module'
VERSION = '0.1.0'
DESCRIPTION = 'Async X-Sense cloud, MQTT, and camera client'

with open('README.rst', 'r') as fd:
LONG_DESCRIPTION = fd.read()
Expand All @@ -11,26 +11,33 @@
version=VERSION,
description=DESCRIPTION,
long_description=LONG_DESCRIPTION,
long_description_content_type='text/x-rst',
url='https://github.com/theosnel/python-xsense',
license='MIT',
author='Theo Snelleman',
author_email='<python@theo.snelleman.net>',
packages=find_packages(),
python_requires='>=3.10',
install_requires=[
'requests',
'boto3',
'botocore',
'pycognito',
'aiohttp',
'paho-mqtt>=2.1.0',
],
extras_require={'async': ['aiohttp']},
extras_require={
'test': ['pytest'],
},

keywords=['python', 'xsense'],
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Education',
'License :: OSI Approved :: MIT License',
'Intended Audience :: Developers',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Programming Language :: Python :: 3.13',
'Operating System :: OS Independent',
]
)
)
35 changes: 0 additions & 35 deletions test.py

This file was deleted.

Loading