summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Zhineng <[email protected]>2025-07-18 14:53:03 +0800
committerLi Zhineng <[email protected]>2025-07-18 14:53:28 +0800
commit0654a9093510f88502bb5e92aa9af41dd319853c (patch)
tree3285625e77a41cd6e789bdc620c3621e73085403
parent3597fb51743f3723cc7d87a049442d574a74a856 (diff)
downloadairmx-0654a9093510f88502bb5e92aa9af41dd319853c.tar.gz
airmx-0654a9093510f88502bb5e92aa9af41dd319853c.zip
control a specific device
-rw-r--r--packages/airmx/src/airmx.ts12
-rw-r--r--packages/airmx/src/eagle.test.ts8
-rw-r--r--packages/airmx/src/eagle.ts98
-rw-r--r--packages/airmx/src/types.ts19
4 files changed, 125 insertions, 12 deletions
diff --git a/packages/airmx/src/airmx.ts b/packages/airmx/src/airmx.ts
index e4789f0..5e933ba 100644
--- a/packages/airmx/src/airmx.ts
+++ b/packages/airmx/src/airmx.ts
@@ -10,7 +10,7 @@ import type {
import type { CommandMessage } from './messages.js'
import { EagleControlMesasge } from './messages.js'
-import { EagleStatus } from './eagle.js'
+import { EagleController, EagleStatus } from './eagle.js'
import { Signer } from './util.js'
import { SnowStatus } from './snow.js'
@@ -169,4 +169,14 @@ export class Airmx {
getEagleStatus(deviceId: number) {
return this.#eagles.get(deviceId)
}
+
+ /**
+ * Specify an AIRMX Pro device.
+ *
+ * @param deviceId - The device ID.
+ * @returns The device controller.
+ */
+ device(deviceId: number) {
+ return new EagleController(this, deviceId)
+ }
}
diff --git a/packages/airmx/src/eagle.test.ts b/packages/airmx/src/eagle.test.ts
index 84c5ebb..2af1bd4 100644
--- a/packages/airmx/src/eagle.test.ts
+++ b/packages/airmx/src/eagle.test.ts
@@ -1,5 +1,7 @@
+import type { Message, EagleStatusData } from './types.js'
+
import { EagleStatus } from './eagle.js'
-import { EagleMode, EagleStatusData } from './types.js'
+import { EagleMode } from './types.js'
test('from parses message to eagle status', () => {
const status = EagleStatus.from(12345, createStubStatusData())
@@ -70,7 +72,9 @@ test('isHeaterOff determines if the heater is off', () => {
expect(status.isHeaterOn()).toBe(false)
})
-const createStubStatusData = (data: Partial<EagleStatusData> = {}) => ({
+const createStubStatusData = (
+ data: Partial<EagleStatusData> = {},
+): Message<EagleStatusData> => ({
cmdId: 210,
data: {
cadr: 17,
diff --git a/packages/airmx/src/eagle.ts b/packages/airmx/src/eagle.ts
index 4de587c..87dd1e7 100644
--- a/packages/airmx/src/eagle.ts
+++ b/packages/airmx/src/eagle.ts
@@ -1,4 +1,6 @@
-import type { Message, EagleStatusData } from './types.js'
+import type { Message, EagleStatusData, EagleControlData } from './types.js'
+
+import { Airmx } from './airmx.js'
import { EagleMode } from './types.js'
export class EagleStatus {
@@ -108,4 +110,98 @@ export class EagleStatus {
get version() {
return this.message.data.version
}
+
+ toControlData(): EagleControlData {
+ const { power, heatStatus, mode, cadr, denoise } = this.message.data
+ return { power, heatStatus, mode, cadr, denoise }
+ }
+}
+
+export class EagleController {
+ constructor(
+ private readonly airmx: Airmx,
+ private readonly deviceId: number,
+ ) {}
+
+ on() {
+ this.#send({ power: 1 })
+ }
+
+ off() {
+ this.#send({ power: 0 })
+ }
+
+ heatOn() {
+ this.#send({ heatStatus: 1 })
+ }
+
+ heatOff() {
+ this.#send({ heatStatus: 0 })
+ }
+
+ denoiseOn() {
+ this.#send({ denoise: 1 })
+ }
+
+ denoiseOff() {
+ this.#send({ denoise: 0 })
+ }
+
+ cadr(cadr: number) {
+ this.#send({
+ power: 1,
+ mode: EagleMode.Manual,
+ cadr,
+ })
+ }
+
+ /**
+ * Automate the fan speed based on the data from the air monitor.
+ */
+ ai() {
+ this.#send({
+ power: 1,
+ mode: EagleMode.Ai,
+ })
+ }
+
+ /**
+ * Activate silent mode to minimize fan noise.
+ */
+ silent() {
+ this.#send({
+ power: 1,
+ mode: EagleMode.Silent,
+ })
+ }
+
+ /**
+ * Activate turbo mode for optimum air purification.
+ */
+ turbo() {
+ this.#send({
+ power: 1,
+ mode: EagleMode.Turbo,
+ cadr: 100,
+ })
+ }
+
+ status() {
+ const status = this.airmx.getEagleStatus(this.deviceId)
+
+ if (status === undefined) {
+ throw new Error(
+ `Could not retrieve the status of the device with ID ${this.deviceId}.`,
+ )
+ }
+
+ return status
+ }
+
+ #send(data: Partial<EagleControlData>) {
+ this.airmx.control(this.deviceId, {
+ ...this.status().toControlData(),
+ ...data,
+ })
+ }
}
diff --git a/packages/airmx/src/types.ts b/packages/airmx/src/types.ts
index ef7ab89..5c28d90 100644
--- a/packages/airmx/src/types.ts
+++ b/packages/airmx/src/types.ts
@@ -31,13 +31,20 @@ export interface Message<T> {
sig: string
}
+export enum EagleMode {
+ Manual = 0,
+ Ai,
+ Silent,
+ Turbo,
+}
+
export interface EagleStatusData {
version: string
- power: number
- mode: number
+ power: 0 | 1
+ mode: EagleMode
status: number
- denoise: number
- heatStatus: number
+ denoise: 0 | 1
+ heatStatus: 0 | 1
cadr: number
prm: number
diffPressure1: number
@@ -51,10 +58,6 @@ export interface EagleStatusData {
hepaPercent: number
}
-export enum EagleMode {
- Silent = 2,
-}
-
export enum SensorState {
Sampling = 'sampling',
}