Compare commits

...

7 Commits

8 changed files with 2345 additions and 2205 deletions

4302
package-lock.json generated

File diff suppressed because it is too large Load Diff

100
server/package-lock.json generated
View File

@ -15,7 +15,7 @@
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
"integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
"requires": { "requires": {
"mime-types": "~2.1.18", "mime-types": "2.1.18",
"negotiator": "0.6.1" "negotiator": "0.6.1"
} }
}, },
@ -38,15 +38,15 @@
"integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
"requires": { "requires": {
"bytes": "3.0.0", "bytes": "3.0.0",
"content-type": "~1.0.4", "content-type": "1.0.4",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "~1.1.1", "depd": "1.1.2",
"http-errors": "~1.6.2", "http-errors": "1.6.3",
"iconv-lite": "0.4.19", "iconv-lite": "0.4.19",
"on-finished": "~2.3.0", "on-finished": "2.3.0",
"qs": "6.5.1", "qs": "6.5.1",
"raw-body": "2.3.2", "raw-body": "2.3.2",
"type-is": "~1.6.15" "type-is": "1.6.16"
} }
}, },
"bytes": { "bytes": {
@ -117,36 +117,36 @@
"resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz",
"integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=",
"requires": { "requires": {
"accepts": "~1.3.5", "accepts": "1.3.5",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "1.18.2", "body-parser": "1.18.2",
"content-disposition": "0.5.2", "content-disposition": "0.5.2",
"content-type": "~1.0.4", "content-type": "1.0.4",
"cookie": "0.3.1", "cookie": "0.3.1",
"cookie-signature": "1.0.6", "cookie-signature": "1.0.6",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "~1.1.2", "depd": "1.1.2",
"encodeurl": "~1.0.2", "encodeurl": "1.0.2",
"escape-html": "~1.0.3", "escape-html": "1.0.3",
"etag": "~1.8.1", "etag": "1.8.1",
"finalhandler": "1.1.1", "finalhandler": "1.1.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"merge-descriptors": "1.0.1", "merge-descriptors": "1.0.1",
"methods": "~1.1.2", "methods": "1.1.2",
"on-finished": "~2.3.0", "on-finished": "2.3.0",
"parseurl": "~1.3.2", "parseurl": "1.3.2",
"path-to-regexp": "0.1.7", "path-to-regexp": "0.1.7",
"proxy-addr": "~2.0.3", "proxy-addr": "2.0.3",
"qs": "6.5.1", "qs": "6.5.1",
"range-parser": "~1.2.0", "range-parser": "1.2.0",
"safe-buffer": "5.1.1", "safe-buffer": "5.1.1",
"send": "0.16.2", "send": "0.16.2",
"serve-static": "1.13.2", "serve-static": "1.13.2",
"setprototypeof": "1.1.0", "setprototypeof": "1.1.0",
"statuses": "~1.4.0", "statuses": "1.4.0",
"type-is": "~1.6.16", "type-is": "1.6.16",
"utils-merge": "1.0.1", "utils-merge": "1.0.1",
"vary": "~1.1.2" "vary": "1.1.2"
} }
}, },
"finalhandler": { "finalhandler": {
@ -155,12 +155,12 @@
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"requires": { "requires": {
"debug": "2.6.9", "debug": "2.6.9",
"encodeurl": "~1.0.2", "encodeurl": "1.0.2",
"escape-html": "~1.0.3", "escape-html": "1.0.3",
"on-finished": "~2.3.0", "on-finished": "2.3.0",
"parseurl": "~1.3.2", "parseurl": "1.3.2",
"statuses": "~1.4.0", "statuses": "1.4.0",
"unpipe": "~1.0.0" "unpipe": "1.0.0"
} }
}, },
"forwarded": { "forwarded": {
@ -178,10 +178,10 @@
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"requires": { "requires": {
"depd": "~1.1.2", "depd": "1.1.2",
"inherits": "2.0.3", "inherits": "2.0.3",
"setprototypeof": "1.1.0", "setprototypeof": "1.1.0",
"statuses": ">= 1.4.0 < 2" "statuses": "1.4.0"
} }
}, },
"iconv-lite": { "iconv-lite": {
@ -229,7 +229,7 @@
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
"requires": { "requires": {
"mime-db": "~1.33.0" "mime-db": "1.33.0"
} }
}, },
"morgan": { "morgan": {
@ -237,11 +237,11 @@
"resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz",
"integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=",
"requires": { "requires": {
"basic-auth": "~2.0.0", "basic-auth": "2.0.0",
"debug": "2.6.9", "debug": "2.6.9",
"depd": "~1.1.1", "depd": "1.1.2",
"on-finished": "~2.3.0", "on-finished": "2.3.0",
"on-headers": "~1.0.1" "on-headers": "1.0.1"
} }
}, },
"ms": { "ms": {
@ -277,8 +277,8 @@
"resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz",
"integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=",
"requires": { "requires": {
"process": "^0.11.1", "process": "0.11.10",
"util": "^0.10.3" "util": "0.10.4"
} }
}, },
"path-to-regexp": { "path-to-regexp": {
@ -296,7 +296,7 @@
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz",
"integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==",
"requires": { "requires": {
"forwarded": "~0.1.2", "forwarded": "0.1.2",
"ipaddr.js": "1.6.0" "ipaddr.js": "1.6.0"
} }
}, },
@ -334,7 +334,7 @@
"depd": "1.1.1", "depd": "1.1.1",
"inherits": "2.0.3", "inherits": "2.0.3",
"setprototypeof": "1.0.3", "setprototypeof": "1.0.3",
"statuses": ">= 1.3.1 < 2" "statuses": "1.4.0"
} }
}, },
"setprototypeof": { "setprototypeof": {
@ -355,18 +355,18 @@
"integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
"requires": { "requires": {
"debug": "2.6.9", "debug": "2.6.9",
"depd": "~1.1.2", "depd": "1.1.2",
"destroy": "~1.0.4", "destroy": "1.0.4",
"encodeurl": "~1.0.2", "encodeurl": "1.0.2",
"escape-html": "~1.0.3", "escape-html": "1.0.3",
"etag": "~1.8.1", "etag": "1.8.1",
"fresh": "0.5.2", "fresh": "0.5.2",
"http-errors": "~1.6.2", "http-errors": "1.6.3",
"mime": "1.4.1", "mime": "1.4.1",
"ms": "2.0.0", "ms": "2.0.0",
"on-finished": "~2.3.0", "on-finished": "2.3.0",
"range-parser": "~1.2.0", "range-parser": "1.2.0",
"statuses": "~1.4.0" "statuses": "1.4.0"
} }
}, },
"serve-static": { "serve-static": {
@ -374,9 +374,9 @@
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
"integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
"requires": { "requires": {
"encodeurl": "~1.0.2", "encodeurl": "1.0.2",
"escape-html": "~1.0.3", "escape-html": "1.0.3",
"parseurl": "~1.3.2", "parseurl": "1.3.2",
"send": "0.16.2" "send": "0.16.2"
} }
}, },
@ -396,7 +396,7 @@
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
"requires": { "requires": {
"media-typer": "0.3.0", "media-typer": "0.3.0",
"mime-types": "~2.1.18" "mime-types": "2.1.18"
} }
}, },
"typescript": { "typescript": {

18
smartclient.service Normal file
View File

@ -0,0 +1,18 @@
[Unit]
Description=smartclient
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
GuessMainPID=yes
ExecStart=/usr/bin/npm run server
ExecStop=kill -SIGINT $mainpid
Restart=on-failure
WorkingDirectory=/opt/services/smartclient
[Install]
Alias=smartclient
WantedBy=multi-user.target

View File

@ -27,7 +27,7 @@
<p class="clear"></p> <p class="clear"></p>
</mat-tab> </mat-tab>
<mat-tab label="Heizung"> <mat-tab label="Heizung">
<heatingcontroller topicPre="testTopic" label="testLabel"></heatingcontroller>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>

View File

@ -6,8 +6,9 @@ import { MatTabsModule } from '@angular/material/tabs';
import { MatExpansionModule } from '@angular/material/expansion'; import { MatExpansionModule } from '@angular/material/expansion';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider'; import { MatDividerModule } from '@angular/material/divider';
import { MatInputModule } from '@angular/material/input'
import { MqttclientService } from './mqttclient.service' import { MqttclientService } from './mqttclient.service'
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
import { LedindicatorComponent } from './ledindicator/ledindicator.component'; import { LedindicatorComponent } from './ledindicator/ledindicator.component';
@ -16,6 +17,7 @@ import { LedButtonGroupComponent } from './led-button-group/led-button-group.com
import { NumberFieldComponent } from './number-field/number-field.component'; import { NumberFieldComponent } from './number-field/number-field.component';
import { LedButtonGroup2Component } from './led-button-group2/led-button-group2.component'; import { LedButtonGroup2Component } from './led-button-group2/led-button-group2.component';
import { LedBoxComponent } from './led-box/led-box.component'; import { LedBoxComponent } from './led-box/led-box.component';
import { HeatingControllerComponent } from './heating-controller/heating-controller.component';
@NgModule({ @NgModule({
@ -26,7 +28,8 @@ import { LedBoxComponent } from './led-box/led-box.component';
LedButtonGroupComponent, LedButtonGroupComponent,
NumberFieldComponent, NumberFieldComponent,
LedButtonGroup2Component, LedButtonGroup2Component,
LedBoxComponent LedBoxComponent,
HeatingControllerComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -34,7 +37,9 @@ import { LedBoxComponent } from './led-box/led-box.component';
MatTabsModule, MatTabsModule,
MatExpansionModule, MatExpansionModule,
MatButtonModule, MatButtonModule,
MatDividerModule MatDividerModule,
MatInputModule,
FormsModule
], ],
providers: [ providers: [
MqttclientService MqttclientService

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeatingControllerComponent } from './heating-controller.component';
describe('HeatingControllerComponent', () => {
let component: HeatingControllerComponent;
let fixture: ComponentFixture<HeatingControllerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeatingControllerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeatingControllerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,91 @@
import { Component, Input, OnInit } from '@angular/core'
import { MqttclientService } from '../mqttclient.service'
import {coerceNumberProperty} from '@angular/cdk/coercion'
@Component({
selector: 'heatingcontroller',
template: `
<div [ngStyle]="{ 'text-align': 'center', 'background-color':'lightgrey', 'border-radius':'10px',
'width': '300px', 'padding':'5px', 'margin': '5px 5px 5px 0',
'font-family': 'sans-serif' }">
{{label}}
<p>
<button mat-raised-button color="primary" (click)="clickOff()" [ngStyle]="{'font-size':'100%'}">off</button>
<button mat-raised-button color="accent" (click)="clickOn()" [ngStyle]="{'font-size':'100%'}">on</button>
<button mat-raised-button color="warn" (click)="clickForceOn()" [ngStyle]="{'font-size':'100%'}">forceOn</button>
</p>
<p>
<mat-form-field [ngStyle]="{'margin':'10px', 'width':'40%'}">
<input type="checkbox" [(ngModel)]="enableCurrentTemperature">
<input matInput type="number" placeholder="Current" [(ngModel)]="currentTemperature"
(click)="setCurrentTemperature()" (keyup)="setCurrentTemperature()"
[disabled]="! enableCurrentTemperature">
</mat-form-field>
<mat-form-field [ngStyle]="{'margin':'10px', 'width':'40%'}">
<input type="checkbox" [(ngModel)]="enablePresetTemperature">
<input matInput type="number" placeholder="Preset" [(ngModel)]="presetTemperature"
(click)="setPresetTemperature()" (keyup)="setPresetTemperature()"
[disabled]="! enablePresetTemperature">
</mat-form-field>
</p>
</div>
`
})
export class HeatingControllerComponent implements OnInit {
@Input() topicPre : string = 'invalid'
commandTopic : string = 'invalid'
presetTopic : string = 'invalid'
feedbackPresetTopic : string = 'invalid'
temperatureTopic : string = 'invalid'
feedbackTemperatureTopic : string = 'invalid'
@Input() label : string = 'invalid'
enableCurrentTemperature : boolean = false
currentTemperature : number = 20
enablePresetTemperature : boolean = false
presetTemperature : number = 20
constructor(private mqttclientService : MqttclientService) { }
ngOnInit() {
this.commandTopic = this.topicPre + '/command'
this.presetTopic = this.topicPre + '/presetTemperature'
this.feedbackPresetTopic = this.topicPre + '/presetTemperature/feedback'
this.temperatureTopic = this.topicPre + '/temperature'
this.feedbackTemperatureTopic = this.topicPre + '/temperature/feedback'
this.mqttclientService.register(this.feedbackTemperatureTopic, (message: string) => {
this.currentTemperature = parseInt(message)
})
this.mqttclientService.register(this.feedbackPresetTopic, (message: string) => {
this.presetTemperature = parseInt(message)
})
}
clickOn() {
console.log(`click on for ${this.commandTopic}`)
this.mqttclientService.publish(this.commandTopic, "ON")
}
clickForceOn() {
console.log(`click absent for ${this.commandTopic}`)
this.mqttclientService.publish(this.commandTopic, "FORCE_ON")
}
clickOff() {
console.log(`click off for ${this.commandTopic}`)
this.mqttclientService.publish(this.commandTopic, "OFF")
}
setCurrentTemperature() {
console.log(`click on currentTemperature ${this.currentTemperature}`)
this.mqttclientService.publish(this.temperatureTopic, this.currentTemperature.toString())
}
setPresetTemperature() {
console.log(`click on presetTemperature ${this.presetTemperature}`)
this.mqttclientService.publish(this.presetTopic, this.presetTemperature.toString())
}
}

View File

@ -9,6 +9,7 @@ export class MqttclientService {
private callbacks : Map<string, callbackFunc> = new Map() private callbacks : Map<string, callbackFunc> = new Map()
constructor() { constructor() {
// this.mqttClient = Mqtt.connect('ws://172.16.2.16:9001')
this.mqttClient = Mqtt.connect('ws://127.0.0.1:9001') this.mqttClient = Mqtt.connect('ws://127.0.0.1:9001')
this.mqttClient.on('connect', () => { this.mqttClient.on('connect', () => {
console.log('MQTT connected') console.log('MQTT connected')