Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for EGI HVAC Climate Control Adapter #8513

Closed
wants to merge 8 commits into from
Closed
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
39 changes: 39 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Run Tests and Lint

on:
push:
branches:
- main
- add-egi-hvac-adapter
pull_request:

jobs:
build:
runs-on: ubuntu-latest

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

- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '16' # Use the Node.js version Zigbee2MQTT supports

- name: Install pnpm
run: npm install -g pnpm

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run ESLint
run: pnpm run eslint --fix

- name: Format Code
run: pnpm run pretty:write

- name: Build Project
run: pnpm run build

- name: Run Tests
run: pnpm test
158 changes: 158 additions & 0 deletions src/devices/egihavc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import fz from '../converters/fromZigbee';
import tz from '../converters/toZigbee';
import * as exposes from '../lib/exposes';
import * as reporting from '../lib/reporting';
import {Definition} from '../lib/types';

const e = exposes.presets;
const ea = exposes.access;

const definitions: Definition[] = [
{
zigbeeModel: ['TS0601'],
model: 'EGI_HVAC_Adapter',
vendor: 'Tuya',
description: 'EGI HVAC Climate Control Adapter',
fromZigbee: [
{
cluster: 'manuSpecificTuya',
type: ['commandDataResponse', 'commandDataReport'],
convert: (model, msg, publish, options, meta) => {
const parsedData: Record<string, any> = {};

if (msg.data && msg.data.dpValues) {
msg.data.dpValues.forEach((dpValue: { dp: number; data: Buffer }) => {
const dp = dpValue.dp;
const value = dpValue.data.readUIntBE(0, dpValue.data.length);

switch (dp) {
case 1:
parsedData.state = value === 1 ? 'ON' : 'OFF';
break;
case 2:
parsedData.temperature_set = value;
break;
case 3:
parsedData.temperature_current = value;
break;
case 4:
const modes = ['Cool', 'Heat', 'Dehumidify', 'Fan'];
parsedData.mode = modes[value] || 'unknown';
break;
case 5:
const fanSpeeds = ['Low', 'Medium', 'High', 'Auto'];
parsedData.fan_speed = fanSpeeds[value] || 'unknown';
break;
case 7:
parsedData.set_as_slave = value === 1 ? 'ENABLE' : 'DISABLE';
break;
default:
console.warn(`Unrecognized datapoint ${dp} with value ${value}`);
}
});

publish(parsedData);
}

return parsedData;
},
},
],
toZigbee: [
tz.on_off,
{
key: ['temperature_set'],
convertSet: async (entity, key, value, meta) => {
const data = Buffer.alloc(4);
data.writeUIntBE(Math.round(value as number), 0, 4);
await entity.command(
'manuSpecificTuya',
'dataRequest',
{
seq: (meta as any).seq || 0,
dpValues: [{ dp: 2, datatype: 2, data }],
},
{ disableDefaultResponse: true }
);
},
},
{
key: ['fan_speed'],
convertSet: async (entity, key, value, meta) => {
const fanMapping: Record<string, number> = { Low: 0, Medium: 1, High: 2, Auto: 3 };
await entity.command(
'manuSpecificTuya',
'dataRequest',
{
seq: (meta as any).seq || 0,
dpValues: [{ dp: 5, datatype: 4, data: Buffer.from([fanMapping[value as string]]) }],
},
{ disableDefaultResponse: true }
);
},
},
{
key: ['mode'],
convertSet: async (entity, key, value, meta) => {
const modeMapping: Record<string, number> = { Cool: 0, Heat: 1, Dehumidify: 2, Fan: 3 };
await entity.command(
'manuSpecificTuya',
'dataRequest',
{
seq: (meta as any).seq || 0,
dpValues: [{ dp: 4, datatype: 4, data: Buffer.from([modeMapping[value as string]]) }],
},
{ disableDefaultResponse: true }
);
},
},
{
key: ['set_as_slave'],
convertSet: async (entity, key, value, meta) => {
await entity.command(
'manuSpecificTuya',
'dataRequest',
{
seq: (meta as any).seq || 0,
dpValues: [{ dp: 7, datatype: 1, data: Buffer.from([value === 'ENABLE' ? 1 : 0]) }],
},
{ disableDefaultResponse: true }
);
},
},
],
exposes: [
e.binary('state', ea.STATE_SET, 'ON', 'OFF').withDescription('Power state'),
e.numeric('temperature_set', ea.STATE_SET)
.withValueMin(16)
.withValueMax(32)
.withUnit('°C')
.withDescription('Target temperature'),
e.numeric('temperature_current', ea.STATE)
.withValueMin(-20)
.withValueMax(50)
.withUnit('°C')
.withDescription('Current room temperature'),
e.enum('mode', ea.STATE_SET, ['Cool', 'Heat', 'Dehumidify', 'Fan']).withDescription('System mode'),
e.enum('fan_speed', ea.STATE_SET, ['Low', 'Medium', 'High', 'Auto']).withDescription('Fan speed mode'),
e.binary('set_as_slave', ea.STATE_SET, 'ENABLE', 'DISABLE').withDescription('Set as Slave mode'),
],
meta: {
tuyaDatapoints: [
[1, 'state'],

Check failure on line 142 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.

Check failure on line 142 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.
[2, 'temperature_set'],

Check failure on line 143 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.

Check failure on line 143 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.
[3, 'temperature_current'],

Check failure on line 144 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.

Check failure on line 144 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.
[4, 'mode'],

Check failure on line 145 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.

Check failure on line 145 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.
[5, 'fan_speed'],

Check failure on line 146 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.

Check failure on line 146 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.
[7, 'set_as_slave'],

Check failure on line 147 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.

Check failure on line 147 in src/devices/egihavc.ts

View workflow job for this annotation

GitHub Actions / ci

Type '[number, string]' is not assignable to type 'MetaTuyaDataPointsSingle'.
],
},
configure: async (device, coordinatorEndpoint) => {
const endpoint = device.getEndpoint(1);
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
await endpoint.read('genBasic', ['modelId', 'manufacturerName']);
},
},
];

export default definitions;
2 changes: 2 additions & 0 deletions src/devices/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import ecozy from './ecozy';
import edp from './edp';
import efekta from './efekta';
import egihvac from './devices/egihvac';

Check failure on line 74 in src/devices/index.ts

View workflow job for this annotation

GitHub Actions / ci

Cannot find module './devices/egihvac' or its corresponding type declarations.

Check failure on line 74 in src/devices/index.ts

View workflow job for this annotation

GitHub Actions / ci

Cannot find module './devices/egihvac' or its corresponding type declarations.
import eglo from './eglo';
import elko from './elko';
import enbrighten from './enbrighten';
Expand Down Expand Up @@ -390,6 +391,7 @@
...ecozy,
...edp,
...efekta,
...egihvac,
...eglo,
...elko,
...enbrighten,
Expand Down
Loading