Positivo PCUIRN MCP Server

Positivo PCUIRN MCP Server

Enables control of TV and air conditioner through natural language commands via Cursor or Claude Desktop.

Category
访问服务器

README

Casa Inteligente — Positivo PCUIRN

Control the Positivo Smart Controle Universal 2 (PCUIRN) outside the official app: REST API, web UI, and MCP tools for Cursor / Claude Desktop.

The device is a Tuya-based IR blaster. This project reverse-engineers the Positivo Casa Inteligente mobile API (not Smart Life) and documents how IR commands reach your TV and air conditioner through the cloud.

Disclaimer: This is an unofficial community project. It is not affiliated with Positivo or Tuya. Use at your own risk.

TL;DR

  1. Setup: npm install → copy .env.example → paste Positivo app email + password → configure MCP in Cursor (once)
  2. Use: open Cursor chat and say "liga o ar no 23" or "turn on the TV" — done. No npm start, no device IDs, no Tuya Cloud.

What works

Feature Method Notes
TV power, volume, channels, navigation Cloud IR Works without closing the mobile app
AC on/off, mode, temperature, fan Cloud IR Gree-style button keys (M0_T23_S0)
Device discovery Positivo API / UDP scan positivo.js, discover.js
Local LAN control TuyAPI Optional; only one client at a time
Cursor / Claude chat control MCP server mcp/server.js

Requirements

  • Node.js 18+
  • A Positivo Casa Inteligente account (same email/password as the mobile app)
  • PCUIRN paired in the app with IR remotes configured (TV, AC, etc.)

Setup (5 minutes)

What you actually need

.env variable Required? Used for
POSITIVO_EMAIL Yes Login to Positivo API
POSITIVO_PASSWORD Yes Login to Positivo API
DEVICE_ID No Local LAN only (probe.js, /api/local/status)
DEVICE_LOCAL_KEY No Local LAN only
DEVICE_IP No Local LAN only
TUYA_ACCESS_ID / TUYA_ACCESS_SECRET No Alternative way to get localKey — see SETUP-TUYA.md

Cloud control (TV, AC, API, web UI, MCP) only needs your Positivo app email and password. No Tuya IoT Cloud developer account, no Smart Life, no iot.tuya.com project.

The PCUIRN must already be paired in the Positivo app with your IR remotes (TV, AC, etc.) configured.

Quick start

git clone https://github.com/YOUR_USER/positivo-pcuirn.git
cd positivo-pcuirn

npm install
cp .env.example .env

Edit .env — only these two lines are required:

POSITIVO_EMAIL=your@email.com
POSITIVO_PASSWORD=your_app_password

Then:

npm run build    # install + build frontend (first time only)
npm start        # API + UI → http://localhost:3000

Test from another terminal:

# Health check
curl http://localhost:3000/api/health

# List IR remotes (TV, AC…)
curl http://localhost:3000/api/remotes

# Turn on TV
curl -X POST http://localhost:3000/api/tv/send \
  -H "Content-Type: application/json" \
  -d '{"command":"power"}'

# AC at 23°C (cool, auto fan)
curl -X POST http://localhost:3000/api/ac/send \
  -H "Content-Type: application/json" \
  -d '{"action":"set","mode":0,"temp":23,"fan":0}'

On first run, login happens automatically and the session is saved to storage/session.json (gitignored). You don't need to run any other setup script.

Optional: device ID / localKey (local LAN only)

Skip this if you only use cloud control (TV, AC, Cursor, web UI).

One command does everything — login, list devices, print .env lines, save cache:

node positivo.js

Look for Smart Controle Universal 2 (productId: lwpag3bu0faaowlj). Copy the printed lines into .env only if you need local control (probe.js).

If IP is missing, run node discover.js to find it on your Wi-Fi.

You do not need Tuya IoT Cloud (iot.tuya.com) for normal use — see SETUP-TUYA.md only as a last resort.

Cursor MCP (one-time)

  1. Cursor Settings → MCP → add server (see mcp/cursor-mcp.example.json)
  2. Set the absolute path to mcp/server.js
  3. Restart Cursor

The MCP server uses the same .env (email + password). npm start does not need to be running for Cursor control.

Development (split API + UI)

# Terminal 1
npm run dev

# Terminal 2
npm run frontend:dev      # http://localhost:5173 (proxies to API)

How to use

After setup, pick how you want to control things. No device IDs, no curl, no Tuya Cloud required for the options below.

1. Cursor / Claude — just ask (recommended)

With MCP configured, talk to the AI in normal language. It calls the tools and sends IR commands over the cloud.

You don't need npm start running. Only .env with email + password.

Examples (Portuguese or English — both work):

You say What happens
"Liga o ar no 23" AC on, cool mode, 23°C
"Desliga o ar" AC off
"Coloca o ar em 16 graus" Sets temperature to 16°C
"Liga a TV" TV power
"Aumenta o volume da TV" Volume up
"Turn on the AC at 23 degrees" Same as above
"Mute the TV" TV mute

The agent picks the right MCP tool (ac_set_temperature, tv_power, etc.) automatically. You never type tool names yourself.

If something fails, check that MCP is enabled in Cursor and .env has the correct Positivo credentials.

2. Web UI

npm start

Open http://localhost:3000 — buttons for TV and AC (mode, temperature, fan).

3. API / curl / scripts

With npm start running:

curl -X POST http://localhost:3000/api/ac/send \
  -H "Content-Type: application/json" \
  -d '{"action":"set","mode":0,"temp":23,"fan":0}'

Or without the server:

node test-control.js send TV power
node test-control.js send "Ar condicionado" "power off"

How it was built (reverse engineering)

1. The hardware

Item Value
Product Positivo Smart Controle Universal 2
Internal name PCUIRN
Tuya productId lwpag3bu0faaowlj
Role IR gateway — exposes virtual remotes (TV, AC) as Tuya sub-devices

The gateway stores learned IR codes. Virtual remotes appear as separate devices under your account.

2. Positivo uses Tuya, but not Smart Life

The official app talks to Tuya's mobile API at https://a1.tuyaus.com/api.json (US region). Authentication uses the same account as the Positivo app — not a Tuya IoT Cloud developer project.

App credentials (clientId, signing secret, virtual deviceId) were extracted from the Positivo Casa Inteligente APK. They live in positivo.js and are app-level constants, not user secrets. Your personal credentials go only in .env.

3. Request signing

Every API call is signed with HMAC-SHA256. The implementation in positivo.js follows the Tuya mobile SDK:

  1. Sort selected query parameters
  2. Hash postData with a custom MD5 shuffle (mobileHash)
  3. Build key=value||key=value string
  4. Sign with the app secret

Password login uses RSA encryption of the MD5-hashed password (encPassword), matching Tuya's mobile flow.

4. Session management

After login, a sid (session id) is cached in storage/session.json (gitignored). The client revalidates the session and re-logins when it expires.

5. Listing devices

tuya.m.location.list
  → tuya.m.my.group.device.list (per home/group)
    → tuya.m.device.get (per device → deviceId, localKey, ip, productId)

node positivo.js prints everything you need for .env and writes devices.json locally (also gitignored).

6. IR remotes and buttons

IR remotes are sub-devices of the gateway:

tuya.m.device.sub.list          # list remotes (TV, AC, …)
tuya.m.infrared.record.get      # remote metadata
tuya.m.infrared.keydata.get     # button list + compressed IR payloads
tuya.m.device.dp.publish        # send IR (DPS payload)

Important constants discovered:

Constant Value Meaning
IR_VENDOR 3 Vendor code for Positivo IR payloads
Gateway productId lwpag3bu0faaowlj Used to auto-detect the PCUIRN

Each button maps to a DPS object. Learned buttons use study_key; preloaded Gree AC codes use send_ir with a compressed pulse and extension field 99999.

7. Gree air conditioner key format

The AC remote uses Tuya's standard Gree encoding. Button names follow:

M{mode}_T{temp}_S{fan}     # cool/heat/auto/dry
M2_S{fan}                    # fan-only mode (no temperature)
Mode Value
Cool 0
Heat 1
Fan 2
Auto 3
Dry 4

Examples: M0_T23_S0 = cool 23°C auto fan, power on / power off for toggle.

This mapping is in lib/commands.js.

8. Cloud vs local control

Cloud (recommended): tuya.m.device.dp.publish via the Positivo API. The gateway receives the command over the internet. No need to close the mobile app.

Local (optional): Direct TCP to the device with TuyAPI using DEVICE_ID, DEVICE_LOCAL_KEY, and DEVICE_IP. Only one connection at a time — close the app first. Test with node probe.js.

LAN discovery: node discover.js broadcasts on Tuya UDP ports 6666/6667 to find devices on your Wi-Fi.

9. Alternative: Tuya IoT Cloud (optional, rarely needed)

Only for local LAN control when node positivo.js does not return a localKey. Cloud IR does not use this. See SETUP-TUYA.md.


REST API

Base URL: http://localhost:3000

Method Endpoint Description
GET /api/health Health check
GET /api/devices List account devices
GET /api/commands TV/AC command catalog
GET /api/remotes IR remotes on the gateway
GET /api/remotes/:name/buttons Buttons for a remote
POST /api/tv/send Send TV command ({ "command": "power" })
POST /api/ac/send Send AC action
POST /api/ir/send Raw IR ({ "remote": "TV", "button": "power" })
GET /api/local/status Local DPS via TuyAPI

Examples

# List remotes
curl http://localhost:3000/api/remotes

# TV power
curl -X POST http://localhost:3000/api/tv/send \
  -H "Content-Type: application/json" \
  -d '{"command":"power"}'

# AC: cool mode, 23°C, auto fan
curl -X POST http://localhost:3000/api/ac/send \
  -H "Content-Type: application/json" \
  -d '{"action":"set","mode":0,"temp":23,"fan":0}'

# AC off
curl -X POST http://localhost:3000/api/ac/send \
  -H "Content-Type: application/json" \
  -d '{"action":"off"}'

Web UI

See How to use → Web UI.


MCP server (reference)

Tools exposed to Cursor / Claude Desktop. For day-to-day use, just ask in chat — see How to use → Cursor.

Tools

Tool Action
tv_power TV power toggle
tv_volume_up / tv_volume_down Volume
tv_mute Mute
tv_channel_up / tv_channel_down Channels
tv_ok / tv_menu Navigation
tv_send Any catalog command by id
ac_power_on / ac_power_off AC power
ac_set Mode + temp + fan (numeric)
ac_set_temperature Set temp (cool mode)
ac_set_mode Set mode by name
list_commands Show available commands

Cursor config

{
  "mcpServers": {
    "casa-inteligente": {
      "command": "node",
      "args": ["/absolute/path/to/positivo-pcuirn/mcp/server.js"]
    }
  }
}

Claude Desktop

Same config in ~/Library/Application Support/Claude/claude_desktop_config.json (macOS).


CLI scripts

Script Purpose
node positivo.js Login + list devices, write devices.json
node positivo.js --login Force fresh login
node discover.js UDP scan for Tuya devices on LAN
node probe.js Test local TuyAPI connection
node cloud.js List devices via Tuya IoT Cloud
node test-control.js list List devices (service layer)
node test-control.js send TV power Send IR via cloud
npm run mcp Run MCP server (stdio)

Project structure

lib/
  positivo-client.js   # Tuya mobile API + IR layer
  commands.js          # TV/AC command catalog (Gree keys)
  service.js           # Shared service for API + MCP
  local-device.js      # TuyAPI local connection
positivo.js            # Login, signing, session cache
src/server.js          # Express API + static UI
mcp/server.js          # MCP stdio server
frontend/              # React UI
storage/session.json   # Cached login session (gitignored)
devices.json           # Device cache from positivo.js (gitignored)

Security & secrets

Never commit:

File Contains
.env Your email, password, device keys
storage/session.json Active API session
devices.json Device IDs, local keys, IPs
.cursor/mcp.json Local IDE paths

Copy .env.example.env and use devices.example.json as a reference for the cache format.

If localKey values were ever committed or shared, rotate them by removing and re-adding the device in the Positivo app, then re-run node positivo.js.

The CLIENT_ID / SECRET_KEY in positivo.js are embedded in the public APK — they identify the app, not your account.


License

MIT — see LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选