Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
y509144 authored Jan 17, 2023
1 parent 0a32bfc commit bc7163a
Show file tree
Hide file tree
Showing 7 changed files with 364 additions and 0 deletions.
18 changes: 18 additions & 0 deletions weather-forecast-widget/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2019 Software AG, Darmstadt, Germany and/or its licensors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { WeatherForecastWidgetModule } from "./weather-forecast-widget.module";
24 changes: 24 additions & 0 deletions weather-forecast-widget/weather-forecast-widget.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.weather-forecast-container {
display: flex;
justify-content: center;
}

.weather-group {
float: left;
margin-left: 10px;
margin-right: 10px;
}

.weather-image-container, .weather-date-container {
padding-right: 3px;
text-align: center;
}

.weather-attribute-title {
padding-right: 3px;
text-align: right;
}

.weather-image-container img {
height: 65px;
}
42 changes: 42 additions & 0 deletions weather-forecast-widget/weather-forecast-widget.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<ng-container *ngIf="weather_forecast">
<div class="weather-forecast-container">
<div class="weather-group" *ngFor="let weather of weather_forecast">
<table>
<tr>
<td class="weather-image-container" colspan="2">
<img src="https://openweathermap.org/img/wn/{{weather.icon}}@2x.png"/>
</td>
</tr>
<tr>
<td class="weather-date-container" colspan="2">
<b>{{weather.date| date:'EEE dd-MMM'}}</b>
</td>
</tr>
<tr>
<td class="weather-attribute-title">
<b>Outlook:</b>
</td>
<td>{{weather.desc}} </td>
</tr>
<tr>
<td class="weather-attribute-title">
<b>Temperature:</b>
</td>
<td>{{weather.temp | number:"1.0-0"}}C</td>
</tr>
<tr>
<td class="weather-attribute-title">
<b>Humidity:</b>
</td>
<td>{{weather.humidity}}%</td>
</tr>
<tr>
<td class="weather-attribute-title">
<b>Wind:</b>
</td>
<td>{{weather.wind.speed | number:"1.0-0"}}mph</td>
</tr>
</table>
</div>
</div>
</ng-container>
142 changes: 142 additions & 0 deletions weather-forecast-widget/weather-forecast-widget.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright (c) 2019 Software AG, Darmstadt, Germany and/or its licensors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Inject, Injectable, Input, OnDestroy } from '@angular/core';
import { Realtime, InventoryService } from '@c8y/client';
import * as _ from 'lodash';
// import { HttpClient } from "@angular/common/http";

@Component({
templateUrl: './weather-forecast-widget.component.html',
styleUrls: ['./weather-forecast-widget.component.css'],
})

// @Injectable({providedIn:"root"})
export class WeatherForecastWidget implements OnDestroy {

widgetConfiguration: any;
weather_forecast: any = <any>[];
forecastRefreshTimer: any;

@Input() set config(newConfig: any) {
this.widgetConfiguration = newConfig;
if( !_.has(this.widgetConfiguration, `weatherAPIConfig.period`)
|| this.widgetConfiguration.weatherAPIConfig.period <= 0 ) {
this.widgetConfiguration.weatherAPIConfig.period = 12;
}
this.updateForDeviceChange( this.widgetConfiguration );
}

constructor(
// private http: HttpClient,
// private realtime: Realtime,
private invSvc: InventoryService) { }

ngOnDestroy(): void {
clearInterval(this.forecastRefreshTimer);
}

private updateForDeviceChange(config) {
// Get the weather forecast data, and filter/transform it
(async () => {
await this.getDeviceLocation( _.get(this.widgetConfiguration, 'device.id') );
await this.updateForecast();
this.forecastRefreshTimer = setInterval( async () => {
await this.updateForecast();
}, this.widgetConfiguration.weatherAPIConfig.period*60*60*1000);
})();
}

private async updateForecast() {
const parent = this;

try {
let getForecastResponse: any;
await this.getForecast(this.widgetConfiguration).then((response)=> response.json()).then((data) => {
getForecastResponse = data;
});
if (getForecastResponse == undefined || !_.has(getForecastResponse, `list`)) {
return;
}

parent.weather_forecast = [];
let allWeather = _.get(getForecastResponse, `list`)
allWeather.forEach(function (item) {
if ((item.dt_txt !== undefined)
&& (item.dt_txt.includes('12:00:00'))) {

let currVal = <any>{};
currVal.date = item.dt_txt.substring(0, 10)
currVal.temp = item.main.temp;
currVal.min_temp = item.main.temp_min;
currVal.max_temp = item.main.temp_max;
currVal.pressure = item.main.pressure;
currVal.humidity = item.main.humidity;
currVal.wind = item.wind;
currVal.overview = item.weather[0].main;
currVal.desc = item.weather[0].description;
currVal.icon = item.weather[0].icon;

parent.weather_forecast.push(currVal);
}
});
} catch(error) {
console.error(error);
}
}

private getForecast(loc: string) {
if ( this.widgetConfiguration.weatherAPIConfig.city ) {
// return this.http.get(`https://api.openweathermap.org/data/2.5/forecast?q=${this.widgetConfiguration.weatherAPIConfig.city}&units=metric&appid=${this.widgetConfiguration.weatherAPIConfig.apikey}`)
return fetch(`https://api.openweathermap.org/data/2.5/forecast?q=${this.widgetConfiguration.weatherAPIConfig.city}&units=metric&appid=${this.widgetConfiguration.weatherAPIConfig.apikey}`);
} else if( this.widgetConfiguration.weatherAPIConfig.latitude && this.widgetConfiguration.weatherAPIConfig.longitude ) {
// return this.http.get(`https://api.openweathermap.org/data/2.5/forecast?lat=${this.widgetConfiguration.weatherAPIConfig.latitude}&lon=${this.widgetConfiguration.weatherAPIConfig.longitude}&units=metric&appid=${this.widgetConfiguration.weatherAPIConfig.apikey}`)
return fetch(`https://api.openweathermap.org/data/2.5/forecast?lat=${this.widgetConfiguration.weatherAPIConfig.latitude}&lon=${this.widgetConfiguration.weatherAPIConfig.longitude}&units=metric&appid=${this.widgetConfiguration.weatherAPIConfig.apikey}`);
} else {
console.log("Weather Widget configuration was not set correctly.")
}
}

private async getDeviceLocation(deviceId: String) {
if( deviceId ) {
const mo = await this.getTargetObject(deviceId);
if (mo && mo.c8y_Position) {
// console.log("Position:" + mo.c8y_Position);
this.widgetConfiguration.weatherAPIConfig.latitude = mo.c8y_Position.lat;
this.widgetConfiguration.weatherAPIConfig.longitude = mo.c8y_Position.lng;
} else if (this.widgetConfiguration.weatherAPIConfig.city === undefined ||
this.widgetConfiguration.weatherAPIConfig.city === '') {
// if the device doesn't have a location, default to London
console.log(`The device selected for the Weather widget does not have a location, defaulting weather widget to 'London'`);
this.widgetConfiguration.weatherAPIConfig.city = 'London';
}
}
}

private getTargetObject(deviceId: String): Promise<any> {
return new Promise( (resolve, reject) => {
this.invSvc.detail(deviceId)
.then( (resp) => {
if (resp.res.status == 200) {
resolve(resp.data);
} else {
reject(resp);
}
});
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<ng-form #configForm="ngForm">

<c8y-form-group>
<label for="weatherAPIConfig">
OpenWeatherAPI Configuration
</label>
</c8y-form-group>

<c8y-form-group>
<label for="openWeather-apikey">
API Key
</label>
<input type="text" name="weatherAPIConfig-apikey" id="openWeather-apikey"
class="form-control bar-chart-control" (change)="onConfigChanged($event)"
[(ngModel)]="weatherAPIConfig.apikey" placeholder='API Key' />
</c8y-form-group>

<c8y-form-group>
<label for="openWeather-period">
Refresh (in hours)
</label>
<input type="text" name="weatherAPIConfig-period" id="openWeather-period"
class="form-control bar-chart-control" (change)="onConfigChanged($event)"
[(ngModel)]="weatherAPIConfig.period" placeholder='Update Period (hours)' />
</c8y-form-group>

<c8y-form-group>
<label for="openWeather-city">
City
</label>
<input type="text" name="weatherAPIConfig-city" id="openWeather-city"
class="form-control bar-chart-control" (change)="onConfigChanged($event)"
[(ngModel)]="weatherAPIConfig.city" placeholder='City (blank=<device location>)' />
</c8y-form-group>
</ng-form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2019 Software AG, Darmstadt, Germany and/or its licensors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input, OnInit } from "@angular/core";
import { ControlContainer, NgForm } from "@angular/forms";
import * as _ from 'lodash';

@Component({
selector: 'weather-forecast-widget-config-component',
templateUrl: './weather-forecast-widget.config.component.html',
viewProviders: [{ provide: ControlContainer, useExisting: NgForm }]
})

export class WeatherForecastWidgetConfig implements OnInit {

@Input() config: any = {};

weatherAPIConfig = {
apikey: '',
latitude: '',
longitude: '',
city: '',
period: ''
};

ngOnInit(): void {
this.initConfig();
}

private initConfig(): void {
if (!this.config) {
return;
}

if (_.has(this.config, 'weatherAPIConfig')) {
this.weatherAPIConfig = _.get(this.config, 'weatherAPIConfig');
}}

onConfigChanged($event: Event): void {
if (!this.weatherAPIConfig.apikey ) {
return;
}
_.set(this.config, 'weatherAPIConfig', { ...this.weatherAPIConfig });
}
}
44 changes: 44 additions & 0 deletions weather-forecast-widget/weather-forecast-widget.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019 Software AG, Darmstadt, Germany and/or its licensors
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CoreModule, HOOK_COMPONENTS } from "@c8y/ngx-components";
import { WeatherForecastWidgetConfig } from "./weather-forecast-widget.config.component";
import { WeatherForecastWidget } from "./weather-forecast-widget.component";
import { NgModule } from "@angular/core";
import { HttpClientModule } from "@angular/common/http";

@NgModule({
imports: [
CoreModule,
HttpClientModule
],
declarations: [WeatherForecastWidget, WeatherForecastWidgetConfig],
entryComponents: [WeatherForecastWidget, WeatherForecastWidgetConfig],
providers: [{
provide: HOOK_COMPONENTS,
multi: true,
useValue: {
id: 'global.presales.weather.forecast.widget',
label: 'Weather Forecast',
description: 'Provides a 5-day weather forecast using OpenWeatherAPI',
component: WeatherForecastWidget,
configComponent: WeatherForecastWidgetConfig,
previewImage: require("../styles/previewImage.png")
}
}],
})
export class WeatherForecastWidgetModule {}

0 comments on commit bc7163a

Please sign in to comment.