-
Notifications
You must be signed in to change notification settings - Fork 1
/
mqtt.js
165 lines (135 loc) · 4.32 KB
/
mqtt.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
const yargs = require('yargs');
const mqtt = require('mqtt');
const { exec } = require('child_process');
const codes = require('./config/config.js');
const argv = yargs
.option('mqttHost', {
description: 'Hostname of MQTT broker',
alias: 'mqtt',
type: 'string'
})
.option('codesend', {
description: 'Path to codesend binary',
type: 'string'
})
.help()
.alias('help', 'h')
.argv;
console.log('init script');
console.log(`args: ${argv}`);
// number of times you want to repeat commands
const commandRepeat = 2;
// queue of commands to run. we have to space out the commands or it'll try to execute commands over one another
let commandQueue = [];
// delay in ms between commands
const commandDelay = 500;
// location of your codesend binary
const codesend = (argv.codesend) ? argv.codesend : '/usr/src/app/433Utils/RPi_utils/codesend';
// current state and brightness
// we're defaulting to off and 100% brightness
console.log('initializing state');
let current_state = {};
let current_brightness = {};
Object.keys(codes).forEach((device) => {
current_state[device] = false;
current_brightness[device] = 100;
});
console.log('creating and starting process queue');
const processQueue = () => {
if (commandQueue.length > 0) {
exec(commandQueue.shift(), (err, stdout, stderr) => {
//console.log(`stdout: ${stdout}`);
//console.log(`stderr: ${stderr}`);
});
}
setTimeout(processQueue, commandDelay);
};
setTimeout(processQueue, commandDelay);
const sendCode = (command, device) => {
for(let i=0; i < commandRepeat; i++) {
let executable = codesend;
if ('script' in codes[device]) {
executable = codes[device]['script'];
}
console.log(`appending: ${executable} ${codes[device][command]}`);
commandQueue.push(`${executable} ${codes[device][command]}`);
}
};
const turnDeviceOn = (device) => {
sendCode('on', device);
client.publish(`${device}/getOn`, 'true');
current_state[device] = true;
};
const turnDeviceOff = (device, brightness) => {
sendCode('off', device);
client.publish(`${device}/getOff`, 'false');
current_state[device] = false;
if (brightness) {
current_brightness[device] = 0;
client.publish(`${device}/getBrightness`, '0');
}
};
// for sending the code, mqtt publish, state
const deviceBrightness = (device, brightness) => {
sendCode(brightness.toString(), device);
client.publish(`${device}/getBrightness`, brightness.toString());
current_brightness[device] = brightness;
};
// for determining the rounded brightness and turning on/off the device
const changeBrightness = (device, brightness) => {
let brightnessLevel = parseInt(brightness);
// we have to round the brightness to the nearest 25% since that's what the controller supports
// there might be a better math way to do this
var roundedBrightness = Math.round(brightnessLevel / 100 * 4) / 4 * 100;
// if we get a 0 brightness, set brightness to 0 and turn off the light
if (roundedBrightness === 0) {
turnDeviceOff(device, true);
} else {
// if the light is off, turn it on
var delay = 0;
if (!current_state[device]) {
turnDeviceOn(device);
delay = 1000;
}
// we can't execute the commands too fast, so delay the brightness change if we just turned them on
setTimeout(() => {
deviceBrightness(device, roundedBrightness)
}, delay);
}
}
//----------------
// MQTT Logic
//----------------
let mqttHost = (argv.mqttHost) ? argv.mqttHost : 'localhost';
console.log(`connecting to mqtt broker ${mqttHost}`);
const client = mqtt.connect(`mqtt://${mqttHost}`);
client.on('connect', () => {
console.log('mqtt connected');
Object.keys(codes).forEach((item) => {
console.log(`subscribing to ${item} statuses`);
client.publish(`${item}/connected`, 'true');
client.subscribe(`${item}/setOn`);
client.subscribe(`${item}/setBrightness`);
});
});
client.on('message', (topic, message) => {
topic = topic.toString();
message = message.toString();
console.log(`new message\ntopic: ${topic}\nmessage: ${message}`);
// expect device/action, like backyard/setOn, and nothing else
if (topic.split('/').length != 2) {
return;
}
let [device, action] = topic.split('/');
if (Object.keys(codes).includes(device)) {
if (action === 'setOn') {
if (message === 'true') {
turnDeviceOn(device);
} else {
turnDeviceOff(device);
}
} else if (action === 'setBrightness') {
changeBrightness(device, message);
}
}
});