Skip to content

Commit 17652a6

Browse files
committed
Programmable timers
1 parent cdb1666 commit 17652a6

File tree

7 files changed

+280
-145
lines changed

7 files changed

+280
-145
lines changed

Diff for: README.md

+118-36
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ Programmable Timer for MQTT messaging.
99
[![Docker Stars](https://badgen.net/docker/stars/legobas/mqtt-timer?icon=docker&label=stars)](https://hub.docker.com/r/legobas/mqtt-timer)
1010
[![Docker Image Size](https://badgen.net/docker/size/legobas/mqtt-timer?icon=docker&label=image%20size)](https://hub.docker.com/r/legobas/mqtt-timer)
1111

12-
## Features
13-
14-
* Standard timers are configurable
15-
* Timers can fire daily or at specific days of the week
16-
* Timers can use daily sunrise & sunset times based on the latitude/longitude coordinates
17-
* Timers can have a fixed offset before or after a timestamp
18-
* Timers can have a random offset before or after a timestamp
19-
* Timers can be removed/reset
20-
* Programmable timers can be specified by MQTT JSON Messages
21-
* Programmable timers are repeatable
22-
* Programmable timers can wait for a random number of seconds/minutes before being fired
23-
* A range of programmable timers can be set with one MQTT message
12+
A timer is one of the most important parts of a home automation system.
13+
It tells lights, thermostats and other devices to adjust at certain times of the day or at specific days of the week.
14+
But in addition to fixed times, a timer must also know the sunrise and sunset times, because they change every day.
15+
This is possible by providing the longitude and latitude coordinates.
16+
Because it is not always dark at the sunset time a timer needs to wait a certain period of time before or after sunrise/sunset.
17+
In some situations it is desirable to wait a random number of seconds or minutes.
18+
This can for example give the impression that someone is home switching the lights on every day at a different time.
19+
Apart from these configurable timers, timers need to be programmable.
20+
An example is the activation of a dimmable light if motion is detected, where the light percentages will go down in the minutes after the detected movement.
21+
Another requirement is option to disable or cancel a timer.
22+
MQTT-Timer aims to meet these needs.
23+
24+
In a MQTT based home automation environment a timer independent from home control software like node-red or Home Assistant increases the stability of the whole system.
25+
It follows the Unix/Linux philosophy: do one thing, and do it well.
26+
If for example node-red crashes the timers will continue to send messages at desired times.
2427

2528
## Installation
2629

@@ -39,24 +42,25 @@ The `mqtt-timer.yml` file has to exist in one of the following locations:
3942

4043
## Configuration options
4144

42-
| Config item | Description |
43-
| ------------------------- | ----------------------------------------------------------------- |
44-
| latitude/longitude | GPS location used for Sunrise/Sunset |
45-
| **MQTT** | |
46-
| URL | MQTT Server URL |
47-
| Username/Password | MQTT Server Credentials |
48-
| QOS | MQTT Server Quality Of Service |
49-
| Retain | MQTT Server Retain messages |
50-
| **Timers** | |
51-
| id | Unique ID for this message (mandatory) |
52-
| time | Time in `15:04` or `15:04:05` format |
53-
| cron | Cron in '`30 7 * * *`' or '`15 30 7 * * *`' (with seconds) format |
54-
| topic | MQTT Topic |
55-
| message | simple string or JSON |
56-
| before, after | offset: fixed number of seconds or minutes |
57-
| randomBefore, randomAfter | offset: random number of seconds or minutes |
58-
59-
Example config.yml:
45+
| Config item | Description |
46+
| ------------------------- | ---------------------------------------------------------------------------- |
47+
| latitude/longitude | GPS location used for Sunrise/Sunset |
48+
| **MQTT** | |
49+
| URL | MQTT Server URL |
50+
| Username/Password | MQTT Server Credentials |
51+
| QOS | MQTT Server Quality Of Service |
52+
| Retain | MQTT Server Retain messages |
53+
| **Timers** | |
54+
| id | Unique ID for this message (mandatory) |
55+
| time | Time in `15:04` or `15:04:05` format |
56+
| cron | Cron expression in '`30 7 * * *`' or '`15 30 7 * * *`' (with seconds) format |
57+
| description | something useful |
58+
| topic | MQTT Topic |
59+
| message | raw string or JSON |
60+
| before, after | offset: fixed number of seconds or minutes |
61+
| randomBefore, randomAfter | offset: random number of seconds or minutes |
62+
63+
Example mqtt-timer.yml:
6064

6165
```yml
6266
latitude: 51.50722
@@ -83,21 +87,99 @@ Example config.yml:
8387
message: off
8488
```
8589
86-
See also: [example/config.yml](example/config.yml)
90+
See also: [Example mqtt-timer.yml](https://github.com/Legobas/mqtt-timer/blob/main/mqtt-timer.yml)
8791
88-
## MQTT JSON messages
92+
## Programmable timers
8993
90-
timer2mqtt/dimmer/set
94+
Timers can be set by sending a MQTT JSON messages to the topic:
95+
96+
MQTT-Timer/set
97+
98+
The JSON message can use the following fields to set a timer:
99+
100+
101+
| Field | Description |
102+
| ----------- | --------------------------------------------------- |
103+
| id | unique ID for this message (mandatory) |
104+
| description | something useful |
105+
| start | '`now`' |
106+
| | duration in '`25 sec`' or '`12 min`' format |
107+
| | time in '`15:04`' or '`15:04:05`' format |
108+
| | if start is omitted the timer will fire immediately |
109+
| repeat | duration in '`25 sec`' or '`12 min`' format |
110+
| repeatUntil | number of times in digit(s) |
111+
| | duration in '`25 sec`' or '`12 min`' format |
112+
| | time in '`15:04`' or '`15:04:05`' format |
113+
| topic | MQTT Topic |
114+
| message | raw string or JSON |
115+
| randomAfter | offset: random number of seconds or minutes |
116+
117+
118+
The JSON message to disable or cancel a timer:
119+
120+
| Field | Description |
121+
| ------- | --------------------------------------------------------- |
122+
| id | unique ID for this message (mandatory) |
123+
| enabled | true or false |
124+
| | true (re-enable) can only be used for configurable timers |
125+
126+
127+
examples:
91128

92129
```json
130+
{
131+
"id": "light001",
132+
"description": "Light on after random max 10 min.",
133+
"start": "now,10 min, 10:15:00",
134+
"randomAfter": "10 min",
135+
"topic": "/homeassistant/light01",
136+
"message": "on",
137+
}
138+
93139
{
94140
"id": "msg001",
95-
"description": "Dim light",
96-
"start": "now",
141+
"description": "Dim light from now every 10 min.",
142+
"start": "now,10 min, 10:15:00",
143+
"repeat": "1 min",
144+
"repeatTimes": 10,
97145
"randomAfter": "1 min",
98146
"topic": "/homeassistant/light04/dimmer",
99-
"message": "10%",
147+
"message": ["100%", "80%", "60%", "20%", "0%"]
100148
}
149+
150+
{
151+
"id": "alarm01",
152+
"description": "Intruder detected",
153+
"start": "now",
154+
"repeat": "1 sec",
155+
"repeatTimes": 100,
156+
"topic": "/homeassistant/light02",
157+
"message": ["on", "off"]
158+
}
159+
```
160+
161+
## Docker
162+
163+
Docker run example:
164+
165+
```bash
166+
$ docker run -d -v /home/legobas/mqtt-timer:/config legobas/mqtt-timer
167+
```
168+
169+
Docker compose example:
170+
171+
```yml
172+
version: "3.9"
173+
174+
services:
175+
MqttTimer:
176+
image: legobas/mqtt-timer
177+
container_name: mqtt-timer
178+
environment:
179+
- TZ=America/New_York
180+
volumes:
181+
- /home/legobas/mqtt-timer:/config
182+
restart: unless-stopped
101183
```
102184

103185
## Timezone

Diff for: config.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ type Timer struct {
3737
RandomAfter string `yaml:"randomAfter"`
3838
Topic string `yaml:"topic"`
3939
Message string `yaml:"message"`
40+
Enabled bool
4041
}
4142

4243
type Config struct {
43-
Debug bool `yaml:"debug"`
4444
Latitude float64 `yaml:"latitude"`
4545
Longitude float64 `yaml:"longitude"`
4646

@@ -90,6 +90,8 @@ func validate(config Config) error {
9090
return errors.New("Config error: MQTT Server URL is mandatory")
9191
}
9292
for _, timer := range config.Timers {
93+
timer.Enabled = true
94+
9395
if timer.Id == "" {
9496
return errors.New("Config error: timer.id is mandatory")
9597
}

Diff for: docker-compose.yml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: "3.9"
2+
3+
services:
4+
MqttTimer:
5+
image: legobas/mqtt-timer:latest
6+
container_name: mqtt-timer
7+
environment:
8+
- TZ=America/New_York
9+
volumes:
10+
- /home/legobas/mqtt-timer:/config
11+
restart: unless-stopped

Diff for: go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ require (
1212
require (
1313
github.com/gorilla/websocket v1.5.0 // indirect
1414
github.com/robfig/cron/v3 v3.0.1 // indirect
15+
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 // indirect
1516
golang.org/x/net v0.7.0 // indirect
1617
golang.org/x/sync v0.1.0 // indirect
1718
)

Diff for: go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
1313
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
1414
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
1515
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
16+
golang.org/x/exp v0.0.0-20230307190834-24139beb5833 h1:SChBja7BCQewoTAU7IgvucQKMIXrEpFxNMs0spT3/5s=
17+
golang.org/x/exp v0.0.0-20230307190834-24139beb5833/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
1618
golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
1719
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
1820
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=

0 commit comments

Comments
 (0)