Compare commits

..

1 Commits

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

View File

@ -11,6 +11,7 @@ let accessLogStream = fs.createWriteStream(path.join(__dirname, '/../../../acces
app.use(morgan('combined', {stream: accessLogStream}))
app.use('/', express.static(path.join(__dirname, '/../../../dist')))
app.use('/config', express.static(path.join(__dirname, '/.././../config')))
app.listen(3000, () => {
console.log('smartclient app listening on port 3000!')

View File

@ -1,18 +0,0 @@
[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>
</mat-tab>
<mat-tab label="Heizung">
<heatingcontroller topicPre="testTopic" label="testLabel"></heatingcontroller>
</mat-tab>
</mat-tab-group>

View File

@ -1,14 +1,15 @@
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http'
import { MatTabsModule } from '@angular/material/tabs';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
import { MatInputModule } from '@angular/material/input'
import { MqttclientService } from './mqttclient.service'
import { FormsModule } from '@angular/forms';
import { ConfigService } from './config.service'
import { AppComponent } from './app.component';
import { LedindicatorComponent } from './ledindicator/ledindicator.component';
@ -17,7 +18,6 @@ import { LedButtonGroupComponent } from './led-button-group/led-button-group.com
import { NumberFieldComponent } from './number-field/number-field.component';
import { LedButtonGroup2Component } from './led-button-group2/led-button-group2.component';
import { LedBoxComponent } from './led-box/led-box.component';
import { HeatingControllerComponent } from './heating-controller/heating-controller.component';
@NgModule({
@ -28,21 +28,20 @@ import { HeatingControllerComponent } from './heating-controller/heating-control
LedButtonGroupComponent,
NumberFieldComponent,
LedButtonGroup2Component,
LedBoxComponent,
HeatingControllerComponent
LedBoxComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
MatTabsModule,
MatExpansionModule,
MatButtonModule,
MatDividerModule,
MatInputModule,
FormsModule
MatDividerModule
],
providers: [
MqttclientService
MqttclientService,
ConfigService
],
bootstrap: [AppComponent]
})

View File

@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { ConfigService } from './config.service';
describe('ConfigService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [ConfigService]
});
});
it('should be created', inject([ConfigService], (service: ConfigService) => {
expect(service).toBeTruthy();
}));
});

25
src/app/config.service.ts Normal file
View File

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { Observable } from 'rxjs/Observable';
export interface Config {
mqttUrl: string
}
@Injectable()
export class ConfigService {
private configUrl : string = 'assets/smartclient.json'
private observableConfig : Observable<Config> = undefined
constructor(private http: HttpClient) {
}
getConfig() : Observable<Config> {
if (this.observableConfig == undefined) {
this.observableConfig = this.http.get<Config>(this.configUrl)
}
return this.observableConfig
}
}

View File

@ -1,25 +0,0 @@
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

@ -1,91 +0,0 @@
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

@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { ConfigService, Config } from './config.service'
import * as Mqtt from 'mqtt'
type callbackFunc = (message: string) => void
@ -7,9 +8,9 @@ type callbackFunc = (message: string) => void
export class MqttclientService {
private mqttClient : Mqtt.MqttClient
private callbacks : Map<string, callbackFunc> = new Map()
private config : Config
constructor() {
// this.mqttClient = Mqtt.connect('ws://172.16.2.16:9001')
constructor(private configService: ConfigService) {
this.mqttClient = Mqtt.connect('ws://127.0.0.1:9001')
this.mqttClient.on('connect', () => {
console.log('MQTT connected')

View File

@ -0,0 +1,3 @@
{
"mqttUrl": "ws://127.0.0.1:9100"
}