Chaweng Buri Resort · Koh Samui · Architecture Plan · Sep 2026

Chaweng Buri Energy Hub

One local-first platform for all resort metering and IoT: the ~120 Tuya villa meters, the Momo Space 3-phase gateway, Zigbee room sensors (door, PIR, air quality), and AC links over Wi-Fi or RS485 — behind a single dashboard the resort owns.

2meters live today (Tuya KWS-302WF + Momo MSP-E3P)
~120meters planned across villas & common areas
2vendor clouds, unified into one CBR-owned data hub
3radio families — Wi-Fi meters, Zigbee sensors, RS485/Wi-Fi AC — one MQTT bus
~360room sensors planned (door + PIR + IAQ per villa)

§1 · The decisionHybrid, local-first — own the data, use clouds only at the edges

Recommended scenario

All device data flows over the resort LAN into a CBR-owned server (MQTT broker + time-series database + web app). The Tuya and Momo clouds are used only for onboarding, key sync, firmware updates and fallback — never as the primary data path.

Why not cloud-only? Three hard constraints make it a dead end at 120 devices:

§2 · ArchitectureFive layers, one adapter seam for every future device

Devices — isolated IoT VLAN, 2.4 GHz SSID, DHCP reservations

~120 Tuya Wi-Fi metersKWS-302WF · local proto 3.4/3.5
Momo Space gatewayMSP-E3P-26217 · 3-phase
Door + PIR + IAQ per villaZigbee 3.0 · ch 25 · zone coordinators (PoE)
AC controllersWi-Fi/Tuya or RS485-Modbus
Water metersModbus RTU/TCP
LAN polling · cloud push · bridged MQTT

Ingest — poller service (Docker on the Ubuntu OptiPlex)

TuyaAdaptertinytuya local poll · 30 s
MomoAdapterREST 5 min → MQTT push 30 s
ZigbeeBridgenormalises Zigbee2MQTT → devices/*
ModbusAdapterRS485 AC + water · 60 s
Occupancy enginedoor+PIR+CO2+PMS → rooms/*/occupancy

Every source normalises to one schema on devices/<type>/<id>/status. Zigbee skips the poller entirely — Zigbee2MQTT publishes MQTT natively; the bridge just renames and tags. Adding a device type = one adapter class. Core never changes.

MQTT (Mosquitto, per-service ACLs, LWT availability)

Store — TimescaleDB (PostgreSQL)

Raw readings 90 days → 15 min / 1 h / daily aggregates for 2 years. Device registry joins meter_id → room_no → HotelTime. Meter↔room mapping is versioned, never overwritten.

Serve — FastAPI + WebSocket

REST for history, registry and control; WebSocket pushes live readings and alerts. JWT auth with admin / supervisor / viewer roles.

HTTPS on staff network

Apps

CBR Energy dashboardReact · live board, rooms, alerts
Grafanaops boards + offline watchdog, day one
LINE notifyalerts to duty manager

The clouds sit off to the side: Tuya Cloud for pairing, local-key sync and OTA; Momo Cloud pushes MQTT via a small VPS relay (~US$5/mo) bridged into the local broker, sidestepping CGNAT.

§3 · Today's two metersSame hub, two very different ingest paths

Tuya (KWS-302WF fleet)Momo Space (MSP-E3P-26217)
RolePer-villa & per-load metering, ~120 unitsCentral 3-phase supply monitoring
Primary pathLAN poll · tinytuya · 30 sMQTT push → VPS relay · 30 s
Interim pathPulsar event queue (cloud push)REST poll every 5 min (free tier)
StatusCloud project ready, 0 devices linkedDraft — Mac ID, tag list, kWh, TLS all TBD
Key riskData-centre mismatch on pairing; local key changes on re-pair; one local connection per deviceMay not report cumulative kWh; RSSI −88 dBm link is marginal; timezone of payload unknown
Before scaling anything: pair one Tuya meter end-to-end (correct EU data centre → local key → poller → DB → dashboard), and dump one raw Momo GETLAST_DATAPOINT response to pin its real schema. Both specs list blocking unknowns that are one afternoon of verification.

§4 · The applicationBuild for the money, not just the pictures

Grafana covers generic dashboards in an afternoon. The custom app earns its keep where the PMS join lives — in priority order:

FeatureWhat it doesWhy
1 · Live boardEvery device: watts now, online/offline, sorted by drawInstant visibility, day one
2 · Per-room historyDay/week/month kWh with cost at PEA tariffkWh per occupied room-night, by room type
3 · Vacant-room waste alertVilla drawing >X W while HotelTime says checked-outAC left running — typically pays for the hardware alone
4 · Baseline anomalyOvernight minimum drifting upwardFailing compressor / pump caught early
5 · ReconciliationSum of all rollups vs the PEA invoiceThe gap = untracked load
6 · Offline watchdogSilent >15 min → LINE alert120 devices means constant quiet dropouts

§5 · Future devicesThe AC link and beyond — a pattern, not a rebuild

Every new device type is one adapter class + one registry entry + one MQTT topic branch. The database schema (narrow metric/value rows) absorbs new metrics without migration.

DeviceProtocolAdapterAdds
AC linkTuya smart AC / IR blaster, or Modbus on VRFReuse TuyaAdapter (new DP map) or ModbusAdapterSetpoint + mode control — auto-shutdown on checkout via HotelTime, the natural sequel to the waste alert
Water metersModbus RTU/TCP, pulse countersModbusAdapterm³ per villa, leak detection from overnight flow
Occupancy / doorsZigbee → Zigbee2MQTTNone — publishes MQTT nativelyPresence signal to sharpen waste alerts
Pool / pump gearTuya breakers or Modbus VFDsExisting adaptersSchedule enforcement, runtime hours

Control commands flow the reverse path — app → MQTT …/commands → adapter → device — with an audit log of who switched what. That's the foundation the AC link plugs into.

§7 · RoadmapProve the chain, then repeat 119 times

01 week

Pilot — prove the whole chain

3 Tuya meters (pool villa, standard room, pool pump) + the Momo gateway + one Zigbee zone kit (1 coordinator, door/PIR/IAQ in 2 rooms). Pair → verify EU data centre → local keys → poller + Zigbee2MQTT → MQTT → TimescaleDB → first Grafana board. Answer every TBD in the Momo spec.

Goal: data from both brands landing in one database.

12–3 wks

One wing (~20 meters) + the registry

Device registry with room_no, offline watchdog, HotelTime join, kWh-per-occupied-night. Sensor-fit the same wing (zone coordinator + 3 sensors per villa) and bring the occupancy engine online. Validate a month against the PEA bill for that wing.

Goal: trust the numbers before scaling.

24–6 wks

App + fleet rollout

FastAPI + React dashboard (live board, room history, occupancy, alerts). Remaining meters + sensor kits in batches of ~20 villas, zone by zone, with an install checklist: pair → verify DC/zone → label → CT direction → registry row → visible in app. Momo moves from REST to MQTT relay.

Goal: all ~120 meters on one dashboard.

3ongoing

Intelligence + future devices

Sensor-confirmed waste alerts, baseline anomaly detection, PEA reconciliation. AC survey → one-unit proof of concept on each transport (Tuya Wi-Fi and RS485) → audited auto-setback pilot on 3 rooms → fleet. Then water meters.

Goal: the platform pays for itself and absorbs any new device.

§8 · Watch-outsThe ten things that actually go wrong

§9 · Cost & footprintOne box, mostly free software

ItemCostNote
On-prem server (Ubuntu OptiPlex, 8 GB / 500 GB SSD)reuse or ~$1,200Handles the full fleet — ~3,100 data points/min is light load
VPS MQTT relay (Momo)~$5/moHolds no data; bridges around CGNAT
Software stack (Mosquitto, TimescaleDB, FastAPI, React, Grafana)$0All open source
Tuya / Momo cloud tiers$0 to startWatch Tuya trial expiry; ask Momo for MQTT/paid pricing
Zigbee: ~6–8 zone coordinators (SLZB-06M PoE) + ~360 sensorshardware quoteVerify models on the Zigbee2MQTT supported list before bulk ordering
AC: Tuya modules / IR blasters or RS485 gateways per bussurvey firstVendor register maps decide the RS485 path
Meters ×120 + licensed installationhardware quoteBatch installs of ~20 with the checklist