More work on server; lots of refactoring and good stuff
This commit is contained in:
parent
4b85395302
commit
f23ad08f92
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
@ -8,7 +8,10 @@
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"program": "${workspaceRoot}/bin/www"
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"program": "${workspaceRoot}/dist/server/index.js"
|
||||
}
|
||||
]
|
||||
}
|
10
.vscode/tasks.json
vendored
10
.vscode/tasks.json
vendored
@ -33,6 +33,16 @@
|
||||
"type": "npm",
|
||||
"script": "start:pretty",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start:dev",
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"type": "npm",
|
||||
"script": "start:watch",
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { MqttApiClient } from "@common/mqtt";
|
||||
import { ISprinklersApi } from "@common/sprinklers";
|
||||
import { MqttApiClient } from "@common/sprinklers/mqtt";
|
||||
|
||||
import { UiMessage, UiStore } from "./ui";
|
||||
export { UiMessage, UiStore };
|
||||
|
@ -1,224 +0,0 @@
|
||||
import { IObservableArray, observable } from "mobx";
|
||||
|
||||
export abstract class Section {
|
||||
device: SprinklersDevice;
|
||||
|
||||
@observable
|
||||
name: string = "";
|
||||
|
||||
@observable
|
||||
state: boolean = false;
|
||||
|
||||
constructor(device: SprinklersDevice) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
run(duration: Duration) {
|
||||
return this.device.runSection(this, duration);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `Section{name="${this.name}", state=${this.state}}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class TimeOfDay {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
millisecond: number;
|
||||
|
||||
constructor(hour: number, minute: number = 0, second: number = 0, millisecond: number = 0) {
|
||||
this.hour = hour;
|
||||
this.minute = minute;
|
||||
this.second = second;
|
||||
this.millisecond = millisecond;
|
||||
}
|
||||
|
||||
static fromDate(date: Date): TimeOfDay {
|
||||
return new TimeOfDay(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
|
||||
}
|
||||
}
|
||||
|
||||
export enum Weekday {
|
||||
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday,
|
||||
}
|
||||
|
||||
export class Schedule {
|
||||
times: TimeOfDay[] = [];
|
||||
weekdays: Weekday[] = [];
|
||||
from: Date | null = null;
|
||||
to: Date | null = null;
|
||||
}
|
||||
|
||||
export class Duration {
|
||||
minutes: number = 0;
|
||||
seconds: number = 0;
|
||||
|
||||
constructor(minutes: number = 0, seconds: number = 0) {
|
||||
this.minutes = minutes;
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
static fromSeconds(seconds: number): Duration {
|
||||
return new Duration(Math.floor(seconds / 60), seconds % 60);
|
||||
}
|
||||
|
||||
toSeconds(): number {
|
||||
return this.minutes * 60 + this.seconds;
|
||||
}
|
||||
|
||||
withSeconds(newSeconds: number): Duration {
|
||||
let newMinutes = this.minutes;
|
||||
if (newSeconds >= 60) {
|
||||
newMinutes++;
|
||||
newSeconds = 0;
|
||||
}
|
||||
if (newSeconds < 0) {
|
||||
newMinutes = Math.max(0, newMinutes - 1);
|
||||
newSeconds = 59;
|
||||
}
|
||||
return new Duration(newMinutes, newSeconds);
|
||||
}
|
||||
|
||||
withMinutes(newMinutes: number): Duration {
|
||||
if (newMinutes < 0) {
|
||||
newMinutes = 0;
|
||||
}
|
||||
return new Duration(newMinutes, this.seconds);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.minutes}M ${this.seconds}S`;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProgramItem {
|
||||
// the section number
|
||||
section: number;
|
||||
// duration of the run
|
||||
duration: Duration;
|
||||
|
||||
constructor(section: number, duration: Duration) {
|
||||
this.section = section;
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
export class Program {
|
||||
device: SprinklersDevice;
|
||||
|
||||
@observable
|
||||
name: string = "";
|
||||
@observable
|
||||
enabled: boolean = false;
|
||||
|
||||
@observable
|
||||
schedule: Schedule = new Schedule();
|
||||
|
||||
@observable
|
||||
sequence: ProgramItem[] = [];
|
||||
|
||||
@observable
|
||||
running: boolean = false;
|
||||
|
||||
constructor(device: SprinklersDevice) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
run() {
|
||||
return this.device.runProgram(this);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `Program{name="${this.name}", enabled=${this.enabled}, schedule=${this.schedule},
|
||||
sequence=${this.sequence}, running=${this.running}}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class SectionRun {
|
||||
id: number;
|
||||
section: number;
|
||||
duration: Duration;
|
||||
startTime: Date | null;
|
||||
pauseTime: Date | null;
|
||||
|
||||
constructor(id: number = 0, section: number = 0, duration: Duration = new Duration()) {
|
||||
this.id = id;
|
||||
this.section = section;
|
||||
this.duration = duration;
|
||||
this.startTime = null;
|
||||
this.pauseTime = null;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `SectionRun{id=${this.id}, section=${this.section}, duration=${this.duration},` +
|
||||
` startTime=${this.startTime}, pauseTime=${this.pauseTime}}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class SectionRunner {
|
||||
device: SprinklersDevice;
|
||||
|
||||
@observable
|
||||
queue: IObservableArray<SectionRun> = observable([]);
|
||||
|
||||
@observable
|
||||
current: SectionRun | null = null;
|
||||
|
||||
@observable
|
||||
paused: boolean = false;
|
||||
|
||||
constructor(device: SprinklersDevice) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
cancelRunById(id: number): Promise<{}> {
|
||||
return this.device.cancelSectionRunById(id);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `SectionRunner{queue="${this.queue}", current="${this.current}", paused=${this.paused}}`;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class SprinklersDevice {
|
||||
@observable
|
||||
connected: boolean = false;
|
||||
|
||||
@observable
|
||||
sections: IObservableArray<Section> = observable.array<Section>();
|
||||
|
||||
@observable
|
||||
programs: IObservableArray<Program> = observable.array<Program>();
|
||||
|
||||
@observable
|
||||
sectionRunner: SectionRunner;
|
||||
|
||||
abstract get id(): string;
|
||||
|
||||
abstract runSection(section: number | Section, duration: Duration): Promise<{}>;
|
||||
|
||||
abstract runProgram(program: number | Program): Promise<{}>;
|
||||
|
||||
abstract cancelSectionRunById(id: number): Promise<{}>;
|
||||
|
||||
abstract pauseSectionRunner(): Promise<{}>;
|
||||
|
||||
abstract unpauseSectionRunner(): Promise<{}>;
|
||||
|
||||
toString(): string {
|
||||
return `SprinklersDevice{id="${this.id}", connected=${this.connected},
|
||||
sections=${this.sections},
|
||||
programs=${this.programs},
|
||||
sectionRunner=${this.sectionRunner} }`;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ISprinklersApi {
|
||||
start(): void;
|
||||
|
||||
getDevice(id: string): SprinklersDevice;
|
||||
|
||||
removeDevice(id: string): void;
|
||||
}
|
41
common/sprinklers/Duration.ts
Normal file
41
common/sprinklers/Duration.ts
Normal file
@ -0,0 +1,41 @@
|
||||
export class Duration {
|
||||
minutes: number = 0;
|
||||
seconds: number = 0;
|
||||
|
||||
constructor(minutes: number = 0, seconds: number = 0) {
|
||||
this.minutes = minutes;
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
static fromSeconds(seconds: number): Duration {
|
||||
return new Duration(Math.floor(seconds / 60), seconds % 60);
|
||||
}
|
||||
|
||||
toSeconds(): number {
|
||||
return this.minutes * 60 + this.seconds;
|
||||
}
|
||||
|
||||
withSeconds(newSeconds: number): Duration {
|
||||
let newMinutes = this.minutes;
|
||||
if (newSeconds >= 60) {
|
||||
newMinutes++;
|
||||
newSeconds = 0;
|
||||
}
|
||||
if (newSeconds < 0) {
|
||||
newMinutes = Math.max(0, newMinutes - 1);
|
||||
newSeconds = 59;
|
||||
}
|
||||
return new Duration(newMinutes, newSeconds);
|
||||
}
|
||||
|
||||
withMinutes(newMinutes: number): Duration {
|
||||
if (newMinutes < 0) {
|
||||
newMinutes = 0;
|
||||
}
|
||||
return new Duration(newMinutes, this.seconds);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `${this.minutes}M ${this.seconds}S`;
|
||||
}
|
||||
}
|
9
common/sprinklers/ISprinklersApi.ts
Normal file
9
common/sprinklers/ISprinklersApi.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { SprinklersDevice } from "./SprinklersDevice";
|
||||
|
||||
export interface ISprinklersApi {
|
||||
start(): void;
|
||||
|
||||
getDevice(id: string): SprinklersDevice;
|
||||
|
||||
removeDevice(id: string): void;
|
||||
}
|
47
common/sprinklers/Program.ts
Normal file
47
common/sprinklers/Program.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { observable } from "mobx";
|
||||
import { Duration } from "./Duration";
|
||||
import { Schedule } from "./schedule";
|
||||
import { SprinklersDevice } from "./SprinklersDevice";
|
||||
|
||||
export class ProgramItem {
|
||||
// the section number
|
||||
section: number;
|
||||
// duration of the run
|
||||
duration: Duration;
|
||||
|
||||
constructor(section: number, duration: Duration) {
|
||||
this.section = section;
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
||||
|
||||
export class Program {
|
||||
device: SprinklersDevice;
|
||||
|
||||
@observable
|
||||
name: string = "";
|
||||
@observable
|
||||
enabled: boolean = false;
|
||||
|
||||
@observable
|
||||
schedule: Schedule = new Schedule();
|
||||
|
||||
@observable
|
||||
sequence: ProgramItem[] = [];
|
||||
|
||||
@observable
|
||||
running: boolean = false;
|
||||
|
||||
constructor(device: SprinklersDevice) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
run() {
|
||||
return this.device.runProgram(this);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `Program{name="${this.name}", enabled=${this.enabled}, schedule=${this.schedule},
|
||||
sequence=${this.sequence}, running=${this.running}}`;
|
||||
}
|
||||
}
|
25
common/sprinklers/Section.ts
Normal file
25
common/sprinklers/Section.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { observable } from "mobx";
|
||||
import { Duration } from "./Duration";
|
||||
import { SprinklersDevice } from "./SprinklersDevice";
|
||||
|
||||
export class Section {
|
||||
device: SprinklersDevice;
|
||||
|
||||
@observable
|
||||
name: string = "";
|
||||
|
||||
@observable
|
||||
state: boolean = false;
|
||||
|
||||
constructor(device: SprinklersDevice) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
run(duration: Duration) {
|
||||
return this.device.runSection(this, duration);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `Section{name="${this.name}", state=${this.state}}`;
|
||||
}
|
||||
}
|
49
common/sprinklers/SectionRunner.ts
Normal file
49
common/sprinklers/SectionRunner.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { IObservableArray, observable } from "mobx";
|
||||
import { Duration } from "./Duration";
|
||||
import { SprinklersDevice } from "./SprinklersDevice";
|
||||
|
||||
export class SectionRun {
|
||||
id: number;
|
||||
section: number;
|
||||
duration: Duration;
|
||||
startTime: Date | null;
|
||||
pauseTime: Date | null;
|
||||
|
||||
constructor(id: number = 0, section: number = 0, duration: Duration = new Duration()) {
|
||||
this.id = id;
|
||||
this.section = section;
|
||||
this.duration = duration;
|
||||
this.startTime = null;
|
||||
this.pauseTime = null;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `SectionRun{id=${this.id}, section=${this.section}, duration=${this.duration},` +
|
||||
` startTime=${this.startTime}, pauseTime=${this.pauseTime}}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class SectionRunner {
|
||||
device: SprinklersDevice;
|
||||
|
||||
@observable
|
||||
queue: IObservableArray<SectionRun> = observable([]);
|
||||
|
||||
@observable
|
||||
current: SectionRun | null = null;
|
||||
|
||||
@observable
|
||||
paused: boolean = false;
|
||||
|
||||
constructor(device: SprinklersDevice) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
cancelRunById(id: number): Promise<{}> {
|
||||
return this.device.cancelSectionRunById(id);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `SectionRunner{queue="${this.queue}", current="${this.current}", paused=${this.paused}}`;
|
||||
}
|
||||
}
|
38
common/sprinklers/SprinklersDevice.ts
Normal file
38
common/sprinklers/SprinklersDevice.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { IObservableArray, observable } from "mobx";
|
||||
import { Duration } from "./Duration";
|
||||
import { Program } from "./Program";
|
||||
import { Section } from "./Section";
|
||||
import { SectionRunner } from "./SectionRunner";
|
||||
|
||||
export abstract class SprinklersDevice {
|
||||
@observable
|
||||
connected: boolean = false;
|
||||
|
||||
@observable
|
||||
sections: IObservableArray<Section> = observable.array<Section>();
|
||||
|
||||
@observable
|
||||
programs: IObservableArray<Program> = observable.array<Program>();
|
||||
|
||||
@observable
|
||||
sectionRunner: SectionRunner;
|
||||
|
||||
abstract get id(): string;
|
||||
|
||||
abstract runSection(section: number | Section, duration: Duration): Promise<{}>;
|
||||
|
||||
abstract runProgram(program: number | Program): Promise<{}>;
|
||||
|
||||
abstract cancelSectionRunById(id: number): Promise<{}>;
|
||||
|
||||
abstract pauseSectionRunner(): Promise<{}>;
|
||||
|
||||
abstract unpauseSectionRunner(): Promise<{}>;
|
||||
|
||||
toString(): string {
|
||||
return `SprinklersDevice{id="${this.id}", connected=${this.connected},
|
||||
sections=${this.sections},
|
||||
programs=${this.programs},
|
||||
sectionRunner=${this.sectionRunner} }`;
|
||||
}
|
||||
}
|
8
common/sprinklers/index.ts
Normal file
8
common/sprinklers/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { IObservableArray, observable } from "mobx";
|
||||
export * from "./Duration";
|
||||
export * from "./ISprinklersApi";
|
||||
export * from "./Program";
|
||||
export * from "./schedule";
|
||||
export * from "./Section";
|
||||
export * from "./SectionRunner";
|
||||
export * from "./SprinklersDevice";
|
172
common/sprinklers/json/index.ts
Normal file
172
common/sprinklers/json/index.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import { assign, pick } from "lodash";
|
||||
import * as s from "..";
|
||||
|
||||
export interface ISectionJSON {
|
||||
name: string;
|
||||
state: boolean;
|
||||
}
|
||||
const sectionProps = ["name", "state"];
|
||||
|
||||
export function sectionToJSON(sec: s.Section): ISectionJSON {
|
||||
return pick(sec, sectionProps);
|
||||
}
|
||||
|
||||
export function sectionFromJSON(sec: s.Section, json: ISectionJSON) {
|
||||
assign(sec, pick(json, sectionProps));
|
||||
}
|
||||
|
||||
export interface ITimeOfDayJSON {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
millisecond: number;
|
||||
}
|
||||
const timeOfDayProps = ["hour", "minute", "second", "millisecond"];
|
||||
|
||||
export function timeOfDayToJSON(timeOfDay: s.TimeOfDay): ITimeOfDayJSON {
|
||||
return pick(timeOfDay, timeOfDayProps);
|
||||
}
|
||||
|
||||
export function timeOfDayFromJSON(timeOfDay: s.TimeOfDay, json: ITimeOfDayJSON) {
|
||||
assign(timeOfDay, pick(json, timeOfDayProps));
|
||||
}
|
||||
|
||||
export interface IScheduleJSON {
|
||||
times: ITimeOfDayJSON[];
|
||||
weekdays: number[];
|
||||
from?: string;
|
||||
to?: string;
|
||||
}
|
||||
const scheduleProps = ["weekdays", "from", "to"];
|
||||
|
||||
export function scheduleToJSON(schedule: s.Schedule): IScheduleJSON {
|
||||
return {
|
||||
...pick(schedule, scheduleProps),
|
||||
times: schedule.times.map(timeOfDayToJSON),
|
||||
};
|
||||
}
|
||||
|
||||
export function scheduleFromJSON(schedule: s.Schedule, json: IScheduleJSON) {
|
||||
assign(schedule, pick(json, scheduleProps));
|
||||
schedule.times.length = json.times.length;
|
||||
schedule.times.forEach((timeOfDay, i) =>
|
||||
timeOfDayFromJSON(timeOfDay, json.times[i]));
|
||||
}
|
||||
|
||||
export interface IProgramItemJSON {
|
||||
section: number;
|
||||
duration: number;
|
||||
}
|
||||
const programItemProps = ["section"];
|
||||
|
||||
export function programItemToJSON(programItem: s.ProgramItem): IProgramItemJSON {
|
||||
return {
|
||||
...pick(programItem, programItemProps),
|
||||
duration: programItem.duration.toSeconds(),
|
||||
};
|
||||
}
|
||||
|
||||
export function programItemFromJSON(programItem: s.ProgramItem, json: IProgramItemJSON) {
|
||||
assign(programItem, pick(json, programItemProps));
|
||||
programItem.duration = s.Duration.fromSeconds(json.duration);
|
||||
}
|
||||
|
||||
export interface IProgramJSON {
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
sequence: IProgramItemJSON[];
|
||||
schedule: IScheduleJSON;
|
||||
running: boolean;
|
||||
}
|
||||
const programProps = ["name", "enabled", "running"];
|
||||
|
||||
export function programToJSON(program: s.Program): IProgramJSON {
|
||||
return {
|
||||
...pick(program, programProps),
|
||||
sequence: program.sequence.map(programItemToJSON),
|
||||
schedule: scheduleToJSON(program.schedule),
|
||||
};
|
||||
}
|
||||
|
||||
export function programFromJSON(program: s.Program, json: IProgramJSON) {
|
||||
assign(program, pick(json, programProps));
|
||||
program.sequence.length = json.sequence.length;
|
||||
program.sequence.forEach((programItem, i) =>
|
||||
programItemFromJSON(programItem, json.sequence[i]));
|
||||
scheduleFromJSON(program.schedule, json.schedule);
|
||||
}
|
||||
|
||||
export interface ISectionRunJSON {
|
||||
id: number;
|
||||
section: number;
|
||||
duration: number;
|
||||
startTime?: number;
|
||||
pauseTime?: number;
|
||||
}
|
||||
const sectionRunProps = ["id", "section", "duration", "startTime", "pauseTime"];
|
||||
|
||||
export function sectionRunToJSON(sectionRun: s.SectionRun): ISectionRunJSON {
|
||||
return pick(sectionRun, sectionRunProps);
|
||||
}
|
||||
|
||||
export function sectionRunFromJSON(sectionRun: s.SectionRun, json: ISectionRunJSON) {
|
||||
assign(sectionRun, pick(json, sectionRunProps));
|
||||
}
|
||||
|
||||
interface ISectionRunnerJSON {
|
||||
queue: ISectionRunJSON[];
|
||||
current: ISectionRunJSON | null;
|
||||
paused: boolean;
|
||||
}
|
||||
const sectionRunnerProps = ["paused"];
|
||||
|
||||
export function sectionRunnerToJSON(sectionRunner: s.SectionRunner): ISectionRunnerJSON {
|
||||
return {
|
||||
...pick(sectionRunner, sectionRunnerProps),
|
||||
queue: sectionRunner.queue.map(sectionRunToJSON),
|
||||
current: sectionRunner.current ? sectionRunToJSON(sectionRunner.current) : null,
|
||||
};
|
||||
}
|
||||
|
||||
export function sectionRunnerFromJSON(sectionRunner: s.SectionRunner, json: ISectionRunnerJSON) {
|
||||
assign(sectionRunner, pick(json, sectionRunnerProps));
|
||||
sectionRunner.queue.length = json.queue.length;
|
||||
sectionRunner.queue.forEach((sectionRun, i) =>
|
||||
sectionRunFromJSON(sectionRun, json.queue[i]));
|
||||
if (json.current == null) {
|
||||
sectionRunner.current = null;
|
||||
} else {
|
||||
if (sectionRunner.current == null) {
|
||||
sectionRunner.current = new s.SectionRun();
|
||||
}
|
||||
sectionRunFromJSON(sectionRunner.current, json.current);
|
||||
}
|
||||
}
|
||||
|
||||
interface ISprinklersDeviceJSON {
|
||||
connected: boolean;
|
||||
sections: ISectionJSON[];
|
||||
sectionRunner: ISectionRunnerJSON;
|
||||
programs: IProgramJSON[];
|
||||
}
|
||||
const sprinklersDeviceProps = ["connected"];
|
||||
|
||||
export function sprinklersDeviceToJSON(sprinklersDevice: s.SprinklersDevice): ISprinklersDeviceJSON {
|
||||
return {
|
||||
...pick(sprinklersDevice, sprinklersDeviceProps),
|
||||
sections: sprinklersDevice.sections.map(sectionToJSON),
|
||||
sectionRunner: sectionRunnerToJSON(sprinklersDevice.sectionRunner),
|
||||
programs: sprinklersDevice.programs.map(programToJSON),
|
||||
};
|
||||
}
|
||||
|
||||
export function sprinklersDeviceFromJSON(sprinklersDevice: s.SprinklersDevice, json: ISprinklersDeviceJSON) {
|
||||
assign(sprinklersDevice, pick(json, sprinklersDeviceProps));
|
||||
sprinklersDevice.sections.length = json.sections.length;
|
||||
sprinklersDevice.sections.forEach((section, i) =>
|
||||
sectionFromJSON(section, json.sections[i]));
|
||||
sectionRunnerFromJSON(sprinklersDevice.sectionRunner, json.sectionRunner);
|
||||
sprinklersDevice.programs.length = json.programs.length;
|
||||
sprinklersDevice.programs.forEach((program, i) =>
|
||||
programFromJSON(program, json.programs[i]));
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import * as mqtt from "mqtt";
|
||||
|
||||
import logger from "./logger";
|
||||
import logger from "@common/logger";
|
||||
import {
|
||||
Duration,
|
||||
ISprinklersApi,
|
||||
@ -12,8 +12,8 @@ import {
|
||||
SectionRunner,
|
||||
SprinklersDevice,
|
||||
TimeOfDay,
|
||||
} from "./sprinklers";
|
||||
import { checkedIndexOf } from "./utils";
|
||||
} from "@common/sprinklers";
|
||||
import { checkedIndexOf } from "@common/utils";
|
||||
|
||||
const log = logger.child({ source: "mqtt" });
|
||||
|
28
common/sprinklers/schedule.ts
Normal file
28
common/sprinklers/schedule.ts
Normal file
@ -0,0 +1,28 @@
|
||||
export class TimeOfDay {
|
||||
hour: number;
|
||||
minute: number;
|
||||
second: number;
|
||||
millisecond: number;
|
||||
|
||||
constructor(hour: number, minute: number = 0, second: number = 0, millisecond: number = 0) {
|
||||
this.hour = hour;
|
||||
this.minute = minute;
|
||||
this.second = second;
|
||||
this.millisecond = millisecond;
|
||||
}
|
||||
|
||||
static fromDate(date: Date): TimeOfDay {
|
||||
return new TimeOfDay(date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
|
||||
}
|
||||
}
|
||||
|
||||
export enum Weekday {
|
||||
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday,
|
||||
}
|
||||
|
||||
export class Schedule {
|
||||
times: TimeOfDay[] = [];
|
||||
weekdays: Weekday[] = [];
|
||||
from: Date | null = null;
|
||||
to: Date | null = null;
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
"@types/classnames": "^2.2.0",
|
||||
"@types/core-js": "^0.9.43",
|
||||
"@types/express": "^4.0.37",
|
||||
"@types/lodash": "^4.14.77",
|
||||
"@types/mqtt": "^0.0.34",
|
||||
"@types/node": "^8.0.6",
|
||||
"@types/object-assign": "^4.0.30",
|
||||
@ -52,6 +53,7 @@
|
||||
"express-pino-logger": "^2.0.0",
|
||||
"extract-text-webpack-plugin": "^3.0.0",
|
||||
"font-awesome": "^4.7.0",
|
||||
"lodash": "^4.17.4",
|
||||
"mobx": "^3.1.11",
|
||||
"mobx-react": "^4.2.1",
|
||||
"module-alias": "^2.0.1",
|
||||
|
@ -3,11 +3,11 @@ import "./configureAlias";
|
||||
import "env";
|
||||
|
||||
import log from "@common/logger";
|
||||
import * as mqtt from "@common/mqtt";
|
||||
import * as mqtt from "@common/sprinklers/mqtt";
|
||||
import { Server } from "http";
|
||||
import app from "./app";
|
||||
|
||||
const mqttClient = new mqtt.MqttApiClient("mqtt://localhost:1882");
|
||||
const mqttClient = new mqtt.MqttApiClient("mqtt://localhost:1883");
|
||||
|
||||
mqttClient.start();
|
||||
|
||||
@ -15,6 +15,14 @@ import { autorun } from "mobx";
|
||||
const device = mqttClient.getDevice("grinklers");
|
||||
autorun(() => log.info("device: ", device.toString()));
|
||||
|
||||
import * as json from "@common/sprinklers/json";
|
||||
|
||||
app.get("/grinklers", (req, res) => {
|
||||
const j = json.sprinklersDeviceToJSON(device);
|
||||
console.dir(device);
|
||||
res.send(j);
|
||||
});
|
||||
|
||||
const server = new Server(app);
|
||||
|
||||
const port = +(process.env.PORT || 8080);
|
||||
|
@ -27,6 +27,10 @@
|
||||
"@types/express-serve-static-core" "*"
|
||||
"@types/serve-static" "*"
|
||||
|
||||
"@types/lodash@^4.14.77":
|
||||
version "4.14.77"
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.77.tgz#0bc699413e84d6ed5d927ca30ea0f0a890b42d75"
|
||||
|
||||
"@types/mime@*":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.1.tgz#2cf42972d0931c1060c7d5fa6627fce6bd876f2f"
|
||||
|
Loading…
x
Reference in New Issue
Block a user