Skip to content

Commit c2e7278

Browse files
authored
Merge pull request #8 from walli545/04-initial-release
04 initial release
2 parents 10ac4b1 + 2865f92 commit c2e7278

File tree

80 files changed

+5350
-1484
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+5350
-1484
lines changed

.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ module.exports = {
44
ecmaVersion: 2018, // Allows for the parsing of modern ECMAScript features
55
sourceType: 'module', // Allows for the use of imports
66
project: './tsconfig.json',
7+
createDefaultProgram: true
78
},
89
extends: [
910
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin

.prettierrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ module.exports = {
55
printWidth: 120,
66
useTabs: true,
77
tabWidth: 4,
8-
endOfLine: 'lf',
8+
endOfLine: 'crlf',
99
};

.travis.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ os:
55

66
language: node_js
77
node_js:
8-
- '6'
98
- '8'
109
- '10'
10+
- '12'
1111

1212
env:
1313
- CXX=g++-4.8
@@ -28,5 +28,6 @@ before_script:
2828
script:
2929
- npm run test:package
3030
- npm run test:unit
31+
- npm run test:ts
3132
- export DEBUG=testing:*
3233
- npm run test:integration

README.md

Lines changed: 37 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,70 +12,46 @@
1212

1313
## time-switch adapter for ioBroker
1414

15-
Time based switching of devices
16-
17-
## Developer manual
18-
This section is intended for the developer. It can be deleted later
19-
20-
### Getting started
21-
22-
You are almost done, only a few steps left:
23-
1. Create a new repository on GitHub with the name `ioBroker.time-switch`
24-
25-
1. Push all files to the GitHub repo. The creator has already set up the local repository for you:
26-
```bash
27-
git push origin master
28-
```
29-
1. Head over to [src/main.ts](src/main.ts) and start programming!
30-
31-
### Scripts in `package.json`
32-
Several npm scripts are predefined for your convenience. You can run them using `npm run <scriptname>`
33-
| Script name | Description |
34-
|-------------|----------------------------------------------------------|
35-
| `build` | Re-compile the TypeScript sources. |
36-
| `watch` | Re-compile the TypeScript sources and watch for changes. |
37-
| `test:ts` | Executes the tests you defined in `*.test.ts` files. |
38-
| `test:package` | Ensures your `package.json` and `io-package.json` are valid. |
39-
| `test:unit` | Tests the adapter startup with unit tests (fast, but might require module mocks to work). |
40-
| `test:integration`| Tests the adapter startup with an actual instance of ioBroker. |
41-
| `test` | Performs a minimal test run on package files and your tests. |
42-
| `coverage` | Generates code coverage using your test files. |
43-
44-
### Writing tests
45-
When done right, testing code is invaluable, because it gives you the
46-
confidence to change your code while knowing exactly if and when
47-
something breaks. A good read on the topic of test-driven development
48-
is https://hackernoon.com/introduction-to-test-driven-development-tdd-61a13bc92d92.
49-
Although writing tests before the code might seem strange at first, but it has very
50-
clear upsides.
51-
52-
The template provides you with basic tests for the adapter startup and package files.
53-
It is recommended that you add your own tests into the mix.
54-
55-
### Publishing the adapter
56-
See the documentation of [ioBroker.repositories](https://github.com/ioBroker/ioBroker.repositories#requirements-for-adapter-to-get-added-to-the-latest-repository).
57-
58-
### Test the adapter manually on a local ioBroker installation
59-
In order to install the adapter locally without publishing, the following steps are recommended:
60-
1. Create a tarball from your dev directory:
61-
```bash
62-
npm pack
63-
```
64-
1. Upload the resulting file to your ioBroker host
65-
1. Install it locally (The paths are different on Windows):
66-
```bash
67-
cd /opt/iobroker
68-
npm i /path/to/tarball.tgz
69-
```
70-
71-
For later updates, the above procedure is not necessary. Just do the following:
72-
1. Overwrite the changed files in the adapter directory (`/opt/iobroker/node_modules/iobroker.time-switch`)
73-
1. Execute `iobroker upload time-switch` on the ioBroker host
15+
This adapter allows the user to switch devices on and off using time schedules.
16+
The schedules can be fully configured by a vis widget.
17+
One schedule switches one ioBroker state and consists of one or more actions that define when and how the state should be switched.
18+
It is possible to configure at which time and on which weekdays the action should be triggered. There can be custom on/off values also.
19+
In the widget the schedule can be disabled temporarily and the switched state can be controlled manually.
20+
21+
![Preview](widgets/time-switch/img/prev/prev-device-schedule.jpg)
22+
23+
## How to setup a schedule
24+
25+
1. Install the adapter and create an instance (one instance can handle many schedules)
26+
2. Go to the instance settings and click "Add schedule" to create a new schedule (one schedule can switch one ioBroker state).
27+
28+
Keep the schedule OID of the newly created schedule in mind, we will need that later.
29+
3. Now go to the vis editor and open the view where the schedule should be visible.
30+
Create a new "Device-Schedule" widget and adjust it's size and position to fit your layout.
31+
4. Now configure the widget with the following properties found under the "Common" attributes:
32+
33+
- dataId: Open the select OID dialog and select the schedule OID that you remembered earlier. It can be found under "time-switch.0".
34+
- stateId: Select the OID of the state that should be switched by the schedule, e.g. on/off status of a wall plug.
35+
- onValue/offValue: Enter the values that represent the devices on/off state, e.g. 0/1, true/false, ON/OFF, ... .
36+
5. The rest can be configured in the view part of the widget.
37+
38+
- Enable/Disable automatic switching
39+
- Change the current value of the state
40+
- Add/Delete/Edit actions
41+
- Change the heading of the schedule plan
42+
43+
## Possible features in the future
44+
45+
- Translations for schedule widget
46+
- Astro actions (switch on sunrise, etc.)
7447

7548
## Changelog
7649

77-
### 0.0.1
78-
* (walli545) initial release
50+
### 1.0.0
51+
* (walli545) initial release, features:
52+
* Admin settings to create schedules
53+
* vis widget to edit schedules and add actions
54+
7955

8056
## License
8157
MIT License

admin/custom_m.html

Lines changed: 0 additions & 44 deletions
This file was deleted.

admin/index_m.html

Lines changed: 86 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<html>
22

33
<head>
4-
54
<!-- Load ioBroker scripts and styles-->
65
<link rel="stylesheet" type="text/css" href="../../css/adapter.css" />
76
<link rel="stylesheet" type="text/css" href="../../lib/css/materialize.css">
@@ -18,76 +17,120 @@
1817
<script type="text/javascript" src="words.js"></script>
1918

2019
<script type="text/javascript">
20+
let g_onChange;
21+
let scheduleIds;
22+
2123
// This will be called by the admin adapter when the settings page loads
2224
function load(settings, onChange) {
23-
// example: select elements with id=key and class=value and insert value
24-
if (!settings) return;
25-
$('.value').each(function () {
26-
var $key = $(this);
27-
var id = $key.attr('id');
28-
if ($key.attr('type') === 'checkbox') {
29-
// do not call onChange direct, because onChange could expect some arguments
30-
$key.prop('checked', settings[id])
31-
.on('change', () => onChange())
32-
;
33-
} else {
34-
// do not call onChange direct, because onChange could expect some arguments
35-
$key.val(settings[id])
36-
.on('change', () => onChange())
37-
.on('keyup', () => onChange())
38-
;
39-
}
25+
g_onChange = onChange;
26+
$('#addSchedule').on('click', function () {
27+
const newId = getNextScheduleId();
28+
scheduleIds.push(newId);
29+
addSchedule(newId);
30+
onChange(true);
4031
});
32+
33+
if (!settings) return;
34+
if (settings.schedules) {
35+
scheduleIds = settings.schedules;
36+
scheduleIds.sort().forEach(s => {
37+
addSchedule(s);
38+
});
39+
}
40+
4141
onChange(false);
42-
// reinitialize all the Materialize labels on the page if you are dynamically adding inputs:
4342
if (M) M.updateTextFields();
4443
}
4544

4645
// This will be called by the admin adapter when the user presses the save button
4746
function save(callback) {
48-
// example: select elements with class=value and build settings object
49-
var obj = {};
50-
$('.value').each(function () {
51-
var $this = $(this);
52-
if ($this.attr('type') === 'checkbox') {
53-
obj[$this.attr('id')] = $this.prop('checked');
47+
callback({schedules: scheduleIds});
48+
g_onChange(false);
49+
}
50+
51+
function addSchedule(scheduleId){
52+
socket.emit('getState', `${adapter}.${instance}.${scheduleId}`, (error, state) => {
53+
let scheduleData;
54+
if (state && state.val) {
55+
scheduleData = JSON.parse(state.val)
5456
} else {
55-
obj[$this.attr('id')] = $this.val();
57+
scheduleData = {actions: [], enabled: false, alias: ''};
5658
}
59+
let enabledText = translateWord(scheduleData.enabled ? 'true' : 'false');
60+
let newRow = `
61+
<tr>
62+
<td>${scheduleId}</td>
63+
<td>${scheduleData.alias}</td>
64+
<td>${scheduleData.actions.length}</td>
65+
<td>${enabledText}</td>
66+
<td>
67+
<a class="delete-schedule values-buttons btn-floating btn-small waves-effect waves-light red"><i class="material-icons" title="Remove schedule">delete</i></a>
68+
</td>
69+
</tr>
70+
`;
71+
72+
$('#schedules').append(newRow);
73+
$('.delete-schedule').on('click', function(){
74+
$(this).parents('tr').remove();
75+
let scheduleId = $(this).parents('tr').find('td').eq(0).text();
76+
scheduleIds = scheduleIds.filter(i => i !== scheduleId);
77+
g_onChange(true);
78+
});
79+
if (M) M.updateTextFields();
5780
});
58-
callback(obj);
5981
}
60-
</script>
6182

83+
function getNextScheduleId() {
84+
const pattern = /(?<=schedule)\d+/;
85+
const mapped = scheduleIds.map(i => i.match(pattern)[0]);
86+
const numbers = mapped
87+
.map(s => Number.parseInt(s, 10))
88+
.sort((a, b) => a-b);
89+
let newIndex = 0;
90+
for (let i = 0; i < numbers.length; i++) {
91+
if (numbers[i] > newIndex) {
92+
break;
93+
} else {
94+
newIndex++;
95+
}
96+
}
97+
return `schedule${newIndex}`;
98+
}
99+
</script>
62100
</head>
63101

64102
<body>
65-
66103
<div class="m adapter-container">
67-
68104
<div class="row">
69105
<div class="col s12 m4 l2">
70106
<img src="time-switch.png" class="logo">
71107
</div>
72108
</div>
73109

74-
<!-- Put your content here -->
75-
76-
<!-- For example columns with settings: -->
77-
<div class="row">
78-
<div class="col s6 input-field">
79-
<input type="checkbox" class="value" id="option1" />
80-
<label for="option1" class="translate">option1</label>
81-
</div>
82-
83-
<div class="col s6 input-field">
84-
<input type="text" class="value" id="option2" />
85-
<label for="option2" class="translate">option2</label>
110+
<div class="row" style="padding-bottom: 0">
111+
<div class="input-field col">
112+
<a class="waves-effect waves-light btn" id="addSchedule">
113+
<i class="material-icons left">add</i><span class="translate">Add schedule</span>
114+
</a>
86115
</div>
87116
</div>
88117

118+
<div class="table-values-div" style="height: calc(100% - 90px); overflow: auto">
119+
<table class="centered highlight">
120+
<thead>
121+
<tr>
122+
<th class="translate">scheduleId</th>
123+
<th class="translate">name</th>
124+
<th class="translate">action count</th>
125+
<th class="translate">enabled</th>
126+
<th class="translate" id="scheduleDelete" style="width: 30px"></th>
127+
</tr>
128+
</thead>
129+
<tbody id="schedules">
130+
</tbody>
131+
</table>
132+
</div>
89133
</div>
90-
91134
</body>
92135

93136
</html>

0 commit comments

Comments
 (0)