Skip to content

Commit 0bee894

Browse files
committed
add: set_thermostat_override action and global tokens for manager
change: add startup method for manager change: token for flow due to circular dependency
1 parent e2136a7 commit 0bee894

File tree

14 files changed

+154
-21
lines changed

14 files changed

+154
-21
lines changed

.vscode/settings.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@
44
"files.trimTrailingWhitespace": true,
55
"editor.tabSize": 4,
66
"editor.useTabStops": true,
7+
8+
"editor.codeActionsOnSave": {
9+
// "source.organizeImports": true,
10+
"source.fixAll": true
11+
},
712
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
"homey:install": "npm run build:app:prod && npm run build:web:prod && athom -p ../homey-heating-dist app install",
7676
"dist": "npm run build:app:prod && npm run build:web:prod && athom -p ../homey-heating-dist app validate --level publish",
7777
"tag": "npm run lint:app && npm run lint:web && npm run test && git tag",
78-
"test": "tsc -p ./src/test/tsconfig.json && mocha",
78+
"test": "rimraf tmp && tsc -p ./src/test/tsconfig.json && mocha",
7979
"release:install": "node scripts/install.js",
8080
"travis:setversion": "node scripts/update-version.js",
8181
"travis:sentry": "sentry-cli",

src/app.json

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,47 @@
171171
]
172172
}
173173
]
174+
},
175+
{
176+
"id": "set_thermostat_override",
177+
"title": {
178+
"en": "Set thermostat mode",
179+
"nl": "Activeer thermostaatmodus"
180+
},
181+
"args": [
182+
{
183+
"type": "dropdown",
184+
"name": "mode",
185+
"values": [
186+
{
187+
"id": "0",
188+
"label": {
189+
"en": "Heating plan (automatic)",
190+
"nl": "Verwarmingsschema (automatisch)"
191+
}
192+
},
193+
{
194+
"id": "6",
195+
"label": {
196+
"en": "Manual until midnight",
197+
"nl": "Handmatig tot middernacht"
198+
}
199+
},
200+
{
201+
"id": "7",
202+
"label": {
203+
"en": "Fully manual",
204+
"nl": "Volledig handmatig"
205+
}
206+
}
207+
]
208+
},
209+
{
210+
"name": "my_device",
211+
"type": "device",
212+
"filter": "driver_id=virtual-thermostat"
213+
}
214+
]
174215
}
175216
],
176217
"triggers": [
@@ -308,4 +349,4 @@
308349
}
309350
}
310351
]
311-
}
352+
}

src/app/app.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
HeatingSchedulerService, ILogger, LoggerFactory, LogService,
88
} from "@app/services";
99
import { App as HomeyApp } from "homey";
10-
import { container, injectable } from "tsyringe";
10+
import { container, inject, injectable } from "tsyringe";
1111

1212
@injectable()
1313
export class HeatingSchedulerApp {
@@ -17,7 +17,7 @@ export class HeatingSchedulerApp {
1717
private loggerFactory: LoggerFactory,
1818
private heatingScheduler: HeatingSchedulerService,
1919
private heatingManager: HeatingManagerService,
20-
private flowService: FlowService) {
20+
@inject("FlowService") private flowService: FlowService) {
2121

2222
this.logger = this.loggerFactory.createLogger("App");
2323
}
@@ -39,7 +39,7 @@ export class HeatingSchedulerApp {
3939
await this.flowService.init();
4040

4141
// apply what we have
42-
await this.heatingManager.applyPlans();
42+
await this.heatingManager.init();
4343

4444
// startup scheduler
4545
await this.heatingScheduler.start();

src/app/services/flow-service/FlowService.ts

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { FlowCardTrigger, FlowCardTriggerDevice } from "homey";
2-
import { container, singleton } from "tsyringe";
1+
import { __, FlowCardTrigger, FlowCardTriggerDevice, FlowToken } from "homey";
2+
import { container, registry, singleton } from "tsyringe";
33
import { HeatingManagerService } from "../heating-manager";
44
import { HeatingPlanRepositoryService } from "../heating-plan-repository";
55
import { HeatingSchedulerService } from "../heating-scheduler";
@@ -11,14 +11,30 @@ import { ModeChangedTrigger, ModeChangedTriggerTokens } from "./ModeChanged";
1111
import { SetLogStateAction } from "./SetLogState";
1212
import { SetModeAction } from "./SetMode";
1313
import { SetPlanStateAction } from "./SetPlanState";
14+
import { SetThermostatOverrideAction } from "./SetThermostatOverride";
1415
import { ThermostatModeChangedTrigger, ThermostatModeChangedTriggerTokens } from "./ThermostatModeChanged";
1516

17+
const FLOWSERVICE_TOKEN = "FlowService";
18+
19+
// to break the cycling dependency
1620
@singleton()
21+
@registry([{ token: FLOWSERVICE_TOKEN, useToken: FlowService }])
1722
export class FlowService {
1823
private logger: ILogger;
1924
private modeChangedTrigger!: FlowCardTrigger<ModeChangedTriggerTokens, void>;
2025
private thermostatModeChangedTrigger!: FlowCardTriggerDevice<ThermostatModeChangedTriggerTokens, void>;
2126

27+
private modeToken!: FlowToken<string>;
28+
private nextDateToken!: FlowToken<string>;
29+
30+
public get nextDate(): FlowToken<string> {
31+
return this.nextDateToken;
32+
}
33+
34+
public get mode(): FlowToken<string> {
35+
return this.modeToken;
36+
}
37+
2238
public get modeChanged(): FlowCardTrigger<ModeChangedTriggerTokens, void> {
2339
return this.modeChangedTrigger;
2440
}
@@ -43,10 +59,27 @@ export class FlowService {
4359
settings: container.resolve<SettingsManagerService>(SettingsManagerService),
4460
};
4561

46-
[ApplyAllAction, ApplyPlanAction, SetLogStateAction, SetModeAction, SetPlanStateAction]
47-
.forEach((action) => action(ctx));
62+
[
63+
ApplyAllAction,
64+
ApplyPlanAction,
65+
SetLogStateAction,
66+
SetModeAction,
67+
SetPlanStateAction,
68+
SetThermostatOverrideAction,
69+
].forEach((action) => {
70+
// tslint:disable-next-line: no-empty
71+
try { action(ctx); } catch { }
72+
});
4873

4974
this.modeChangedTrigger = ModeChangedTrigger(ctx);
5075
this.thermostatModeChangedTrigger = ThermostatModeChangedTrigger(ctx);
76+
77+
this.logger.information(`Registering token mode`);
78+
this.modeToken = new FlowToken<string>("mode", { type: "string", title: __("plans.heatingmode.label") });
79+
await this.modeToken.register();
80+
81+
this.logger.information(`Registering token next_schedule`);
82+
this.nextDateToken = new FlowToken<string>("next_schedule", { type: "string", title: __("temperatures.next") });
83+
await this.nextDateToken.register();
5184
}
5285
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
import { NormalOperationMode, ThermostatMode } from "@app/model";
3+
import { IVirtualThermostat } from "../../../drivers/types";
4+
import { flowCardActionFactory, IFlowContext } from "./args";
5+
6+
type ChangeModeArgs = {
7+
mode: string;
8+
my_device: IVirtualThermostat;
9+
};
10+
11+
export function SetThermostatOverrideAction({ logger }: IFlowContext) {
12+
return flowCardActionFactory<ChangeModeArgs>("set_thermostat_override", logger, async (args, _state) => {
13+
await args.my_device.changeThermostatMode(
14+
parseInt(args.mode, 10) as (ThermostatMode | NormalOperationMode));
15+
return true;
16+
});
17+
}

src/app/services/heating-manager/HeatingManagerService.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ICalculatedTemperature, IGroupedCalculatedTemperature, IHeatingPlan, No
22
import { __, Notification } from "homey";
33
import { forEach, groupBy, isEmpty, map } from "lodash";
44
import { EventDispatcher, IEvent } from "ste-events";
5-
import { container, singleton } from "tsyringe";
5+
import { container, inject, singleton } from "tsyringe";
66
import { HeatingPlanCalculator } from "../calculator";
77
import { AuditedDevice, DeviceManagerService } from "../device-manager";
88
import { FlowService } from "../flow-service";
@@ -44,7 +44,7 @@ export class HeatingManagerService {
4444
private calc: HeatingPlanCalculator,
4545
private deviceManager: DeviceManagerService,
4646
private settings: SettingsManagerService,
47-
private flow: FlowService,
47+
@inject("FlowService") private flow: FlowService,
4848
loggerFactory: LoggerFactory) {
4949
this.logger = loggerFactory.createLogger("Manager");
5050
this.isRunning = false;
@@ -94,13 +94,19 @@ export class HeatingManagerService {
9494
this.mode = mode;
9595
this.settings.set<number>(InternalSettings.OperationMode, mode);
9696

97+
if (this.flow.mode != null) { this.flow.mode.setValue(__(`Modes.${mode}`)); }
98+
this.onModeDispatcher.dispatch(this, mode);
99+
97100
if (this.settings.get(Settings.NotifyModeChange, true)) {
98101
this.sendNotification("set_operation_mode", {
99102
mode: __(`Modes.${mode}`),
100103
});
101104
}
105+
}
102106

103-
this.onModeDispatcher.dispatch(this, mode);
107+
public async init() {
108+
this.flow.mode.setValue(__(`Modes.${this.mode}`));
109+
await this.applyPlans();
104110
}
105111

106112
// erors handled by all callers

src/app/services/heating-scheduler/HeatingSchedulerService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { Mutex, slotTime } from "@app/helper";
33
import { IHeatingPlan, NormalOperationMode, OverrideMode, ThermostatMode } from "@app/model";
44
import { ManagerCron } from "homey";
55
import { first, groupBy, map, sortBy, unionBy } from "lodash";
6-
import { singleton } from "tsyringe";
6+
import { inject, singleton } from "tsyringe";
77
import { HeatingPlanCalculator } from "../calculator";
8+
import { FlowService } from "../flow-service";
89
import { HeatingManagerService } from "../heating-manager";
910
import { HeatingPlanRepositoryService } from "../heating-plan-repository";
1011
import { asynctrycatchlog, ICategoryLogger, LoggerFactory, trycatchlog } from "../log";
@@ -29,6 +30,7 @@ export class HeatingSchedulerService {
2930
private calculator: HeatingPlanCalculator,
3031
private repository: HeatingPlanRepositoryService,
3132
private settings: SettingsManagerService,
33+
@inject("FlowService") private flow: FlowService,
3234

3335
loggerFactory: LoggerFactory) {
3436
this.logger = loggerFactory.createLogger("Scheduler");
@@ -211,6 +213,10 @@ export class HeatingSchedulerService {
211213
this.logger.information(`Next execution is at ${this.next.toLocaleString()}`, plansToExecute.map((p) => `${p.name} (${p.id})`));
212214
const task = await ManagerCron.registerTask(taskName, this.next, plansToExecute);
213215

216+
if (this.flow.nextDate != null) {
217+
this.flow.nextDate.setValue(this.next.toLocaleString());
218+
}
219+
214220
if (this.next === END_OF_DAY) {
215221
task.once("run", this.clearOverrides.bind(this));
216222
} else {

src/app/services/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Order is important for dependency injection!
22
export * from "./settings-manager";
33
export * from "./log";
4+
45
export * from "./homey-api";
56
export * from "./calculator";
67
export * from "./heating-scheduler";
78
export * from "./device-manager";
89
export * from "./heating-plan-repository";
9-
export * from "./heating-manager";
1010
export * from "./flow-service";
11-
11+
export * from "./heating-manager";
1212
export * from "./bootstrapper";

src/drivers/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { NormalOperationMode, ThermostatMode } from "@app/model";
2+
import { Device } from "homey";
3+
4+
export interface IVirtualThermostat extends Device {
5+
changeThermostatMode(mode: ThermostatMode | NormalOperationMode): Promise<void>;
6+
}

0 commit comments

Comments
 (0)