Skip to content

Sevenfortyseven/PawKit

Repository files navigation

Pawkit

A native iOS replacement for the SmartLife app, scoped to a single device — the MPets SMARTO M500 automatic litter box (Tuya model ALB201). Built because SmartLife is buggy and slow, and the device's protocol turned out to be reverse-engineerable.

Status: early development. The Tuya v3.4 local protocol is fully ported to Swift and proven against the live device. The iOS UI is next.

What works today

$ swift run pawkit-cli
connecting to 192.168.1.99:6668…
✓ connected, session key established
→ reading status…
DP map (18 keys):
  DP 5    = int(5)        # delay_clean_time
  DP 6    = int(3871)     # cat_weight (g)
  DP 7    = int(1)        # excretion_times_day
  DP 16   = bool(true)    # light
  DP 22   = int(2)        # fault bitmap
  DP 24   = string("standby")
  ...

Decoded state:
  status: standby
  cat weight: 3871 g  (3.871 kg)
  delay clean: 5 min
  light: true  child_lock: false  button_sound: true  kitten_mode: false
  faults: cover_box_not_in_place

End-to-end read and write (pawkit-cli --toggle-light flips DP 16 off→on through the local protocol).

Architecture

Hybrid local + cloud, via a single LitterBoxClient protocol with two implementations:

PawkitCore (Swift Package)
├── TuyaProtocol.swift      wire constants, frame type, command enum
├── TuyaCipher.swift        AES-128-ECB + HMAC-SHA256 + session-key derivation
├── TuyaMessageCodec.swift  pack/unpack v3.4 frames (the bit/byte layer)
├── TuyaError.swift
├── Models.swift            TuyaDPValue, LitterBoxState, fault bitmap, sleep config
└── LocalClient.swift       NWConnection async client w/ status / setDP / events

The local protocol handles 95% of operations. A cloud client (planned) will cover the few settings that don't expose locally — delay_clean_time writes propagate cloud→device with a 1–3 min lag, factory_reset is cloud-only, and schedules are cloud-stored.

DP map

The full reverse-engineered datapoint reference — including the fault bitmap, the 5-byte schedule packing format, and the cat-session push-event encoding — is in dp_map.md. 18 of ~19 visible DPs are confirmed, plus 2 push-event DPs.

Building

Requires macOS 13+ / iOS 16+ and Swift 5.9.

cd PawkitCore
swift test                              # cipher + codec unit tests
swift build                              # builds the library + CLI
.build/debug/pawkit-cli                  # connect, read, decode
.build/debug/pawkit-cli --toggle-light   # full read+write smoke test

Pairing & credentials

Pawkit doesn't implement Tuya BLE pairing — that's a much larger protocol, and a one-time setup. The flow is:

  1. Pair the device once via SmartLife (standard Tuya account binding).
  2. Create a Smart Home project at iot.tuya.com, authorize IoT Core, Authorization Token Management, and Smart Home Basic Service.
  3. Link your SmartLife account to the project (Devices → Link Tuya App Account).
  4. Run bootstrap.py once to fetch your devId and localKey into .env.
  5. From there, pawkit talks directly to the device on TCP port 6668 — no SmartLife needed for daily use.

If you ever factory-reset the device, you'll need SmartLife again to re-pair (the localKey rotates). For day-to-day operation it stays out of the way.

Acknowledgments

  • tinytuya — the open-source Python library whose protocol implementation made this port possible. Pawkit's Swift v3.4 layer is faithful to tinytuya's wire format.
  • The countless Home Assistant / localtuya contributors who've documented Tuya quirks over the years.

License

Personal project, no formal license yet. If you want to use this as a reference for your own Tuya device, fork freely.

About

Custom app for automatic cat litter

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors