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
42 changes: 42 additions & 0 deletions .github/workflows/code_quality.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Code Quality

on:
pull_request:
branches:
- master
push:

jobs:
code_quality:
name: ${{ matrix.name }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- id: black
name: Check code with black
- id: isort
name: Check code with isort
- id: pylint
name: Check code with pylint
- id: mypy
name: Check code with mypy
steps:
- name: Checkout the repository
uses: actions/checkout@v4

- name: Set up Python 3
uses: actions/setup-python@v5
id: python
with:
python-version: "3.11"

- name: Install workflow dependencies
run: |
pip install -r .github/workflows/requirements.txt

- name: Install Python dependencies
run: poetry install --no-interaction

- name: Run ${{ matrix.id }} checks
run: poetry run ${{ matrix.id }} src
36 changes: 36 additions & 0 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: "CodeQL"

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write

strategy:
fail-fast: false
matrix:
language: ["python"]

steps:
- name: Checkout repository
uses: actions/checkout@v5

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@v4

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
23 changes: 0 additions & 23 deletions .github/workflows/pylint.yml

This file was deleted.

43 changes: 43 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Publish release

on:
release:
types: [published]

jobs:
build-and-publish-pypi:
name: Builds and publishes release to PyPI
runs-on: ubuntu-latest
outputs:
version: ${{ steps.vars.outputs.tag }}
steps:
- uses: actions/checkout@v5

- name: Set up Python 3.11
uses: actions/setup-python@v6
with:
python-version: "3.11"

- name: Install workflow dependencies
run: |
pip install -r .github/workflows/requirements.txt

- name: Install dependencies
run: poetry install --no-interaction

- name: Set package version
run: |
version="${{ github.event.release.tag_name }}"
version="${version,,}"
version="${version#v}"
poetry version --no-interaction "${version}"

- name: Build package
run: poetry build --no-interaction

- name: Publish to PyPi
env:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
run: |
poetry config pypi-token.pypi "${PYPI_TOKEN}"
poetry publish --no-interaction
2 changes: 2 additions & 0 deletions .github/workflows/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pip>=23.3
poetry==1.5.1
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
[![GitHub Latest Release][releases_shield]][latest_release]
[![PyPI][pypi_releases_shield]][pypi_latest_release]
[![PyPI - Downloads][pypi_downloads_shield]][pypi_downloads]

[latest_release]: https://github.com/maksp86/Python-package-vacuum-map-parser-ijai/releases/latest
[releases_shield]: https://img.shields.io/github/v/release/maksp86/Python-package-vacuum-map-parser-ijai

[pypi_latest_release]: https://pypi.org/project/vacuum-map-parser-ijai/
[pypi_releases_shield]: https://img.shields.io/pypi/v/vacuum-map-parser-ijai

[pypi_downloads]: https://pepy.tech/project/vacuum-map-parser-ijai
[pypi_downloads_shield]: https://static.pepy.tech/badge/vacuum-map-parser-ijai

# Vacuum map parser - Ijai

Expand Down Expand Up @@ -36,6 +48,13 @@ unpacked_map = parser.unpack_map(raw_map,
device_mac='**:**:**:**:**:**')
parsed_map = parser.parse(unpacked_map)
```

## Supported vacuums:
- ijai.vacuum.* (at least v1, v2, v3, v10, v13, v18, v19)
- xiaomi.vacuum.c103
- xiaomi.vacuum.c104
- xiaomi.vacuum.b106eu
*If you got another vacuum to work, please tell us*

## Special thanks

Expand Down
39 changes: 28 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,30 @@ version = "0.0.0"
license = "Apache-2.0"
description = "Functionalities for Ijai vacuum map parsing"
readme = "README.md"
authors = ["Alexander Vassilyevsky <[email protected]>"]
authors = ["maksp86 <[email protected]>", "Alexander Vassilyevsky <[email protected]>"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Environment :: Console",
"Programming Language :: Python :: 3.11",
"Topic :: Home Automation",
]
packages = [
{ include = "vacuum_map_parser_ijai", from = "src" },
]
packages = [{ include = "vacuum_map_parser_ijai", from = "src" }]

[tool.poetry.urls]
"Homepage" = "https://github.com/Tarh-76/Python-package-vacuum-map-parser-ijai"
"Repository" = "https://github.com/Tarh-76/Python-package-vacuum-map-parser-ijai"
"Bug Tracker" = "https://github.com/Tarh-76/Python-package-vacuum-map-parser-ijai/issues"
"Changelog" = "https://github.com/Tarh-76/Python-package-vacuum-map-parser-ijai/releases"
"Homepage" = "https://github.com/maksp86/Python-package-vacuum-map-parser-ijai"
"Repository" = "https://github.com/maksp86/Python-package-vacuum-map-parser-ijai"
"Bug Tracker" = "https://github.com/maksp86/Python-package-vacuum-map-parser-ijai/issues"
"Changelog" = "https://github.com/maksp86/Python-package-vacuum-map-parser-ijai/releases"

[tool.poetry.dependencies]
python = "^3.11"
Pillow = "*"
vacuum-map-parser-base = "0.1.2"
pycryptodome = "*"

vacuum-map-parser-base = ">=0.1.5"

[tool.poetry.dev-dependencies]
[tool.poetry.group.dev.dependencies]
black = "*"
mypy = "*"
ruff = "*"
Expand All @@ -45,6 +45,12 @@ line_length = 120

[tool.mypy]
platform = "linux"
exclude = '''(?x)
( ^.*RobotMap_pb2\.py$
| ^.*RobotMap_pb2\.pyi$
| ^.*beautify_min\.py$
)
'''

check_untyped_defs = true
disallow_any_generics = true
Expand All @@ -64,7 +70,18 @@ warn_unused_configs = true
warn_unused_ignores = true

[tool.pylint]
disable = ["C0103", "C0116", "R0902", "R0903", "R0912", "R0913", "R0914", "R0915", "W0640"]
disable = [
"C0103",
"C0116",
"R0902",
"R0903",
"R0912",
"R0913",
"R0914",
"R0915",
"W0640",
"R0917",
]
max-line-length = 120

[build-system]
Expand Down
2 changes: 2 additions & 0 deletions src/vacuum_map_parser_ijai/RobotMap_pb2.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 12 additions & 7 deletions src/vacuum_map_parser_ijai/aes_decryptor.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
"""Module that provides functions for decrypting a map."""

import base64
import binascii

from Crypto.Cipher import AES
from Crypto.Hash import MD5
from Crypto.Util.Padding import pad, unpad
import base64


isEncryptKeyTypeHex = True

def aes_encrypt(data, key: str):

def aes_encrypt(data: str, key: str) -> str:
cipher = AES.new(key.encode("utf-8"), AES.MODE_ECB)

encryptedData = cipher.encrypt(
Expand All @@ -15,7 +19,8 @@ def aes_encrypt(data, key: str):

return encryptedBase64Str

def aes_decrypt(data, key: str):

def aes_decrypt(data: bytes, key: str) -> bytes:
parsedKey = key.encode("utf-8")
if isEncryptKeyTypeHex:
parsedKey = bytes.fromhex(key)
Expand All @@ -29,7 +34,7 @@ def aes_decrypt(data, key: str):
return bytes.fromhex(decryptedData.decode("utf-8"))


def md5key(string: str, model: str, device_mac: str):
def md5key(string: str, model: str, device_mac: str) -> str:
pjstr = "".join(device_mac.lower().split(":"))

tempModel = model.split('.')[-1]
Expand All @@ -50,7 +55,7 @@ def md5key(string: str, model: str, device_mac: str):
return temp[8:-8].upper()


def gen_md5_key(wifi_info_sn: str, owner_id: str, device_id: str, model: str, device_mac: str):
def gen_md5_key(wifi_info_sn: str, owner_id: str, device_id: str, model: str, device_mac: str) -> str:
arr = [wifi_info_sn, owner_id, device_id]
tempString = '+'.join(arr)
return md5key(tempString, model, device_mac)
Expand All @@ -59,6 +64,6 @@ def gen_md5_key(wifi_info_sn: str, owner_id: str, device_id: str, model: str, de
def decrypt(data: bytes, wifi_info_sn: str, owner_id: str, device_id: str, model: str, device_mac: str) -> bytes:
try:
data = base64.b64decode(data, validate=True)
except:
except binascii.Error:
pass
return aes_decrypt(data, gen_md5_key(wifi_info_sn, owner_id, device_id, model, device_mac))
13 changes: 8 additions & 5 deletions src/vacuum_map_parser_ijai/beautify_min.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# pylint: skip-file
import collections

from vacuum_map_parser_base.map_data import Point

from vacuum_map_parser_ijai.RobotMap_pb2 import RobotMap
import collections


class BeautifyMap:
Expand Down Expand Up @@ -33,7 +36,7 @@ def setMap(self, mapData: RobotMap.MapDataInfo):

self.map = tempArray

def normalizeMap(self):
def normalizeMap(self) -> None:
# normalizing all data to bytes and values suitable for map_data_parser
for i in range(len(self.map)):
if self.map[i] < 0:
Expand All @@ -45,10 +48,10 @@ def normalizeMap(self):
elif self.map[i] == 40:
self.map[i] = 255

def getMap(self):
def getMap(self) -> list[int]:
return self.map

def transform(self):
def transform(self) -> None:
non_boundary_noise = []
self.findRoiMap()
self.expandBlackRect(4, 4, self.map[0])
Expand Down Expand Up @@ -927,7 +930,7 @@ def searchLineForNewSeed(self, dst: list[int], x_left, x_right, line_row, raw_va

return scan_line_seed

def fillInternalObstacles(self):
def fillInternalObstacles(self) -> None:
if (self.tRect["width"] == 0 and self.tRect["height"] == 0):
self.findRoiMap()

Expand Down
Loading