... | ... | @@ -42,54 +42,103 @@ Lets build our Datasource plugin! |
|
|
First create a new file `plugins/weatherDatasource.js`
|
|
|
And add some code:
|
|
|
|
|
|
(function (window) {
|
|
|
|
|
|
const TYPE_INFO = {
|
|
|
type: 'simpleweatherjs-ds',
|
|
|
name: 'Weather',
|
|
|
description: 'Receive Weather data from Yahoo!',
|
|
|
dependencies: ['https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js'],
|
|
|
settings: [
|
|
|
{
|
|
|
id: 'unitType',
|
|
|
name: 'Units',
|
|
|
type: 'option',
|
|
|
defaultValue: 'metric',
|
|
|
options: [
|
|
|
{name: 'Metric', value: 'metric'},
|
|
|
{name: 'Imperial', value: 'imperial'}
|
|
|
]
|
|
|
},
|
|
|
{
|
|
|
id: 'location',
|
|
|
name: "Location",
|
|
|
type: 'string',
|
|
|
description: 'lat/lon, US zip code, or location name for Yahoo! weather API',
|
|
|
defaultValue: 'Austin, TX'
|
|
|
}
|
|
|
]
|
|
|
};
|
|
|
|
|
|
const Plugin = function (props) {
|
|
|
};
|
|
|
```
|
|
|
// We wrap the code into an anonymous function that is executed immediately to not pollute the global namespace.
|
|
|
// More about JavaScript Module pattern: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html
|
|
|
(function () {
|
|
|
|
|
|
// First define a JavaScript object with metadata for the plugin.
|
|
|
// The object must be serializable, i.e. there must not be any function definitions inside
|
|
|
const TYPE_INFO = {
|
|
|
// The type is the primary key of the plugin an must be globally unique
|
|
|
type: 'simpleweatherjs-ds',
|
|
|
// The name is displayed to the user to name the Plugin
|
|
|
name: 'Weather',
|
|
|
// The kind is 'datasource' or 'widget' and used internally
|
|
|
kind: 'datasource',
|
|
|
// Take some credits in the author field
|
|
|
author: 'Lobaro',
|
|
|
// Use semantic version to version your plugins, it helps to keep track of changes
|
|
|
version: '1.0.0',
|
|
|
// A Description is shown in the UI to explain what the plugin does
|
|
|
description: 'Receive Weather data from Yahoo!',
|
|
|
// JavaScript and CSS dependencies can be loaded here
|
|
|
// We do not load jQuery here because it's provided by the Dashboard - This will change in future!
|
|
|
dependencies: ['https://cdnjs.cloudflare.com/ajax/libs/jquery.simpleWeather/3.1.0/jquery.simpleWeather.min.js'],
|
|
|
// The settings array describes the options shown in the config dialog of the plugin
|
|
|
settings: [
|
|
|
{
|
|
|
// The id is unique for each plugin and is used to reference the setting value in code
|
|
|
id: 'unitType',
|
|
|
// The name is displayed next to the field
|
|
|
name: 'Units',
|
|
|
// There are several types, here we let the user choose one of multiple options from a drop down box
|
|
|
type: 'option',
|
|
|
// The default value is referencing the 'value' that is selected by default
|
|
|
defaultValue: 'metric',
|
|
|
options: [
|
|
|
// Each option can have a name and a value, where the name is displayed to the user and the value is used in code
|
|
|
{name: 'Metric', value: 'metric'},
|
|
|
{name: 'Imperial', value: 'imperial'}
|
|
|
]
|
|
|
},
|
|
|
{
|
|
|
id: 'location',
|
|
|
name: "Location",
|
|
|
// The string type just renders a string input field
|
|
|
type: 'string',
|
|
|
// The description is optional and shows a little hint icon with details about the setting
|
|
|
description: 'lat/lon, US zip code, or location name for Yahoo! weather API',
|
|
|
defaultValue: 'Austin, TX'
|
|
|
}
|
|
|
]
|
|
|
};
|
|
|
|
|
|
// Plugins are compiled with Babel
|
|
|
// This means we can use ES6 JavaScript features like classes and do not have to care about older browsers. Babel will make it work!
|
|
|
class Plugin {
|
|
|
|
|
|
constrctor(props) {
|
|
|
// Any code that is required to execute when the plugin is loaded the first time e.g. setting up some properties
|
|
|
// Set how often fetchData() will be called, 'Infinite' to disable regular updates
|
|
|
props.setFetchInterval(10 * 1000); // Fetch every 10 seconds, and once after the plugin is loaded.
|
|
|
props.setFetchReplaceData(true);
|
|
|
}
|
|
|
|
|
|
Plugin.prototype.fetchData = function(fulfill, reject) {
|
|
|
const settings = this.props.state.settings;
|
|
|
// The only required function
|
|
|
fetchData(fulfill, reject) {
|
|
|
// Return data via the fulfill callback, that should be rendered by Widgets
|
|
|
// Data must be an 'array' containing 'objects', e.g. [{temp: 23.5}, {temp: 23.3}]
|
|
|
// resolve and reject are callbacks, to allow returning data from async callbacks
|
|
|
// Per default, resolved data is appended to the datasource (see props.setFetchReplaceData above)
|
|
|
// fetchData() is called when the datasource is created, after settings changed and regularly depending on the value of setFetchInterval(intervalInMs: number)
|
|
|
|
|
|
// We can always access the datasource properties we saw in the constructor via this.props
|
|
|
// Via the state we can access the setting values set by the user
|
|
|
const settingValues = this.props.state.settings;
|
|
|
// Call the simpleWeather jQuery plugin according to the documentation
|
|
|
$.simpleWeather({
|
|
|
location: settings["location"],
|
|
|
// The "location" property of settingValues holds the value of the setting with the id "location"
|
|
|
location: settingValues["location"],
|
|
|
woeid: '',
|
|
|
unit: settings["unitType"] === 'metric' ? 'c' : 'f',
|
|
|
unit: settingValues["unitType"] === 'metric' ? 'c' : 'f',
|
|
|
success: function (weather) {
|
|
|
// On success we call our fulfill callback and handover the data
|
|
|
fulfill([weather]);
|
|
|
},
|
|
|
error: function (error) {
|
|
|
// On error we tell the dashboard not to wait for data any longer
|
|
|
// Else the dashboard would wait for timeout and print an error to the console
|
|
|
reject(error);
|
|
|
}
|
|
|
})
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
window.iotDashboardApi.registerDatasourcePlugin(TYPE_INFO, Plugin)
|
|
|
})(window);
|
|
|
// Now we just have to handover our TYPE_INFO object and Plugin class to the dashboard API to load them
|
|
|
window.iotDashboardApi.registerDatasourcePlugin(TYPE_INFO, Plugin)
|
|
|
})();
|
|
|
```
|
|
|
|
|
|
Now open the Dashboard in your browser and go to `Plugins` -> URL Field: `./plugins/weatherDatasource.js` -> `Load Plugin`
|
|
|
|
... | ... | @@ -107,54 +156,77 @@ Widgets are React components that get all required API via the props. For more d |
|
|
Create a new file `plugins/weatherWidget.js`
|
|
|
And add some code:
|
|
|
|
|
|
(function (window) {
|
|
|
|
|
|
const TYPE_INFO = {
|
|
|
type: 'simpleweatherjs-widget',
|
|
|
name: 'Weather',
|
|
|
description: 'Visualize Weather data',
|
|
|
settings: [
|
|
|
{
|
|
|
id: 'datasource',
|
|
|
name: 'Datasource',
|
|
|
type: 'datasource',
|
|
|
description: "Datasource to get the weather data"
|
|
|
}
|
|
|
]
|
|
|
};
|
|
|
|
|
|
class Plugin extends React.Component {
|
|
|
render() {
|
|
|
const props = this.props;
|
|
|
const settings = props.state.settings;
|
|
|
|
|
|
const allData = props.getData(settings.datasource);
|
|
|
|
|
|
|
|
|
if(allData.length === 0) {
|
|
|
return <div>No Data {JSON.stringify(data)}</div>
|
|
|
}
|
|
|
```
|
|
|
// The structure of a Widget plugin is very similar to a DataSource
|
|
|
// Please see the comments at the weather datasource if you miss something here.
|
|
|
(function (window) {
|
|
|
|
|
|
const TYPE_INFO = {
|
|
|
type: 'simpleweatherjs-widget',
|
|
|
name: 'Weather',
|
|
|
kind: 'widget',
|
|
|
author: 'Lobaro',
|
|
|
version: '1.0.0',
|
|
|
description: 'Visualize Weather data',
|
|
|
settings: [
|
|
|
{
|
|
|
id: 'datasource-setting',
|
|
|
name: 'Datasource',
|
|
|
// datasource is a special type that let the user select a datasource
|
|
|
// The widget will only have access to data from assigned datasources
|
|
|
// If you need more than one datasource, you can specify multiple settings
|
|
|
type: 'datasource',
|
|
|
description: "Datasource to get the weather data"
|
|
|
}
|
|
|
]
|
|
|
};
|
|
|
|
|
|
// A Widget is based on a ReactJS Component
|
|
|
// React is available to all plugins and must not be declared as dependency
|
|
|
class Plugin extends React.Component {
|
|
|
// Beside all optional lifecycle methods of React you must specify a render method
|
|
|
// Render is called when ever settings change or a
|
|
|
render() {
|
|
|
// Like in the datasource we can access props via 'this.props'
|
|
|
const props = this.props;
|
|
|
// And the settings are saved in the same location as for datasources
|
|
|
const settingValues = props.state.settings;
|
|
|
|
|
|
// The getData() function returns data from the datasource, just hand over the selected datasource from the settings
|
|
|
// The dashboard will always return an array of object
|
|
|
const allData = props.getData(settingValues['datasource-setting']);
|
|
|
|
|
|
// When there is no data, we let the user know by rendering a static text
|
|
|
if (allData.length === 0) {
|
|
|
// We can use 'jsx' syntax here. Babel will compile the <div> to:
|
|
|
// return React.createElement('div', null, 'No Data');
|
|
|
return <div>No Data</div>
|
|
|
}
|
|
|
|
|
|
const data = allData[allData.length - 1];
|
|
|
const units = data.units || {};
|
|
|
// Since we just want to show the last fetched value from the datasource we take the last element
|
|
|
const data = allData[allData.length - 1];
|
|
|
const units = data.units || {};
|
|
|
|
|
|
return <div style={{padding: 5}}>
|
|
|
<h1>{data.city}, {data.country}</h1>
|
|
|
return (
|
|
|
<div style={{padding: 5}}>
|
|
|
<h1 style={{marginTop: 0}}>{data.city}, {data.country}</h1>
|
|
|
<p>{data.updated}</p>
|
|
|
<p><img className="ui left floated small image" src={data.image} />
|
|
|
<p><img className="" style={{float: 'left'}} src={data.image}/>
|
|
|
<span>
|
|
|
Temp: {data.temp} {units.temp}<br />
|
|
|
Humidity: {data.humidity} %<br />
|
|
|
Pressure: {data.pressure} {units.pressure}
|
|
|
</span>
|
|
|
Temp: {data.temp} {units.temp}<br />
|
|
|
Humidity: {data.humidity} %<br />
|
|
|
Pressure: {data.pressure} {units.pressure}
|
|
|
</span>
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
}
|
|
|
</div>
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
window.iotDashboardApi.registerWidgetPlugin(TYPE_INFO, Plugin)
|
|
|
})(window);
|
|
|
```
|
|
|
|
|
|
window.iotDashboardApi.registerWidgetPlugin(TYPE_INFO, Plugin)
|
|
|
})(window);
|
|
|
|
|
|
|
|
|
* Now open the Dashboard in your browser and go to `Plugins` -> Load from URL: `plugins/weatherWidget.js` -> `Load Plugin`
|
... | ... | |