-
-
Notifications
You must be signed in to change notification settings - Fork 75
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
670 additions
and
351 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
const Valetudo = require("./Valetudo"); | ||
const Valetudo = require("./lib/Valetudo"); | ||
new Valetudo(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
const fs = require("fs"); | ||
const Tools = require("./Tools"); | ||
const path = require("path"); | ||
|
||
/** | ||
* @constructor | ||
*/ | ||
const Configuration = function() { | ||
this.location = process.env.VALETUDO_CONFIG ? process.env.VALETUDO_CONFIG : "/mnt/data/valetudo/config.json"; | ||
this.settings = { | ||
"spots": [], | ||
"areas": [], | ||
"mqtt" : { | ||
enabled: false, | ||
identifier: "rockrobo", | ||
broker_url: "mqtt://foobar.example" | ||
} | ||
}; | ||
|
||
/* load an existing configuration file. if it is not present, create it using the default configuration */ | ||
if(fs.existsSync(this.location)) { | ||
console.log("Loading configuration file:", this.location); | ||
|
||
try { | ||
this.settings = JSON.parse(fs.readFileSync(this.location)); | ||
} catch(e) { | ||
//TODO: handle this | ||
console.error("Invalid configuration file!"); | ||
throw e; | ||
} | ||
} else { | ||
console.log("No configuration file present. Creating one at:", this.location); | ||
Tools.MK_DIR_PATH(path.dirname(this.location)); | ||
this.persist(); | ||
} | ||
}; | ||
|
||
|
||
/** | ||
* | ||
* @param key {string} | ||
* @returns {*} | ||
*/ | ||
Configuration.prototype.get = function(key) { | ||
return this.settings[key]; | ||
}; | ||
|
||
Configuration.prototype.getAll = function() { | ||
return this.settings; | ||
}; | ||
|
||
/** | ||
* | ||
* @param key {string} | ||
* @param val {string} | ||
*/ | ||
Configuration.prototype.set = function(key, val) { | ||
this.settings[key] = val; | ||
|
||
this.persist(); | ||
}; | ||
|
||
Configuration.prototype.persist = function() { | ||
fs.writeFile(this.location, JSON.stringify(this.settings, null, 2), (err) => { | ||
if (err) { | ||
console.error(err); | ||
} | ||
}); | ||
}; | ||
|
||
module.exports = Configuration; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
const mqtt = require("mqtt"); | ||
|
||
|
||
const COMMANDS = { | ||
turn_on: "turn_on", | ||
return_to_base: "return_to_base", | ||
stop: "stop", | ||
clean_spot: "clean_spot", | ||
locate: "locate", | ||
start_pause: "start_pause", | ||
set_fan_speed: "set_fan_speed" | ||
}; | ||
|
||
//TODO: since this is also displayed in the UI it should be moved somewhere else | ||
const FAN_SPEEDS = { | ||
min: 38, | ||
medium: 60, | ||
high: 75, | ||
max: 100 | ||
}; | ||
|
||
|
||
|
||
/** | ||
* | ||
* @param options {object} | ||
* @param options.vacuum {Vacuum} | ||
* @param options.brokerURL {string} | ||
* @param options.identifier {string} | ||
* @constructor | ||
*/ | ||
const MqttClient = function(options) { | ||
this.vacuum = options.vacuum; | ||
this.brokerURL = options.brokerURL; | ||
this.identifier = options.identifier || "rockrobo"; | ||
|
||
this.topics = { | ||
command: "valetudo/" + this.identifier + "/command", | ||
set_fan_speed: "valetudo/" + this.identifier + "/set_fan_speed", | ||
send_command: "valetudo/" + this.identifier + "/custom_command", | ||
state: "valetudo/" + this.identifier + "/state", | ||
homeassistant_autoconf: "homeassistant/vacuum/valetudo_" + this.identifier + "/config" | ||
}; | ||
|
||
this.connect(); | ||
this.updateStateTopic(); | ||
}; | ||
|
||
MqttClient.prototype.connect = function() { | ||
if(!this.client || (this.client && this.client.connected === false && this.client.reconnecting === false)) { | ||
this.client = mqtt.connect(this.brokerURL); | ||
|
||
this.client.on("connect", () => { | ||
this.client.subscribe([ | ||
this.topics.command, | ||
this.topics.set_fan_speed | ||
], err => { | ||
if(!err) { | ||
this.client.publish(this.topics.homeassistant_autoconf, JSON.stringify({ | ||
name: this.identifier, | ||
supported_features: [ | ||
"turn_on", | ||
"pause", | ||
"stop", | ||
"return_home", | ||
"battery", | ||
"status", | ||
"locate", | ||
"clean_spot", | ||
"fan_speed", | ||
"send_command" | ||
], | ||
command_topic: this.topics.command, | ||
battery_level_topic: this.topics.state, | ||
battery_level_template: "{{ value_json.battery_level }}", | ||
charging_topic: this.topics.state, | ||
charging_template: "{{value_json.charging}}", | ||
cleaning_topic: this.topics.state, | ||
cleaning_template: "{{value_json.cleaning}}", | ||
docked_topic: this.topics.state, | ||
docked_template: "{{value_json.docked}}", | ||
error_topic: this.topics.state, | ||
error_template: "{{value_json.error}}", | ||
fan_speed_topic: this.topics.state, | ||
fan_speed_template: "{{ value_json.fan_speed }}", | ||
set_fan_speed_topic: this.topics.set_fan_speed, | ||
fan_speed_list: [ | ||
"min", | ||
"medium", | ||
"high", | ||
"max" | ||
], | ||
send_command_topic: this.topics.send_command | ||
|
||
}), { | ||
retain: true | ||
}) | ||
} else { | ||
//TODO: needs more error handling | ||
console.error(err); | ||
} | ||
}); | ||
}); | ||
|
||
this.client.on("message", (topic, message) => { | ||
this.handleCommand(topic, message.toString()); | ||
}) | ||
} | ||
}; | ||
|
||
MqttClient.prototype.updateStateTopic = function() { | ||
if(this.stateUpdateTimeout) { | ||
clearTimeout(this.stateUpdateTimeout); | ||
} | ||
|
||
if(this.client && this.client.connected === true) { | ||
this.vacuum.getCurrentStatus((err, res) => { | ||
if(!err) { | ||
var response = {}; | ||
|
||
response.battery_level = res.battery; | ||
response.docked = [8,14].indexOf(res.state) !== -1; | ||
response.cleaning = res.in_cleaning === 1; | ||
response.charging = res.state === 8; | ||
|
||
switch(res.fan_power) { | ||
case FAN_SPEEDS.min: | ||
response.fan_speed = "min"; | ||
break; | ||
case FAN_SPEEDS.medium: | ||
response.fan_speed = "medium"; | ||
break; | ||
case FAN_SPEEDS.high: | ||
response.fan_speed = "high"; | ||
break; | ||
case FAN_SPEEDS.max: | ||
response.fan_speed = "max"; | ||
break; | ||
default: | ||
response.fan_speed = res.fan_power; | ||
} | ||
|
||
if(res.error_code !== 0) { | ||
response.error = res.human_error; | ||
} | ||
|
||
this.client.publish(this.topics.state, JSON.stringify(response)); | ||
this.stateUpdateTimeout = setTimeout(() => { | ||
this.updateStateTopic() | ||
}, 10000); | ||
} else { | ||
console.error(err); | ||
this.stateUpdateTimeout = setTimeout(() => { | ||
this.updateStateTopic() | ||
}, 30000); | ||
} | ||
}) | ||
} else { | ||
this.stateUpdateTimeout = setTimeout(() => { | ||
this.updateStateTopic() | ||
}, 30000); | ||
} | ||
}; | ||
|
||
/** | ||
* @param topic {string} | ||
* @param command {string} | ||
*/ | ||
MqttClient.prototype.handleCommand = function(topic, command) { | ||
var param; | ||
if(topic === this.topics.set_fan_speed) { | ||
param = command; | ||
command = COMMANDS.set_fan_speed; | ||
} | ||
|
||
switch(command) { //TODO: error handling | ||
case COMMANDS.turn_on: | ||
this.vacuum.startCleaning(() => { | ||
this.updateStateTopic(); | ||
}); | ||
break; | ||
case COMMANDS.stop: | ||
this.vacuum.stopCleaning(() => { | ||
this.updateStateTopic(); | ||
}); | ||
break; | ||
case COMMANDS.return_to_base: | ||
this.vacuum.stopCleaning(() => { | ||
this.vacuum.driveHome(() => { | ||
this.updateStateTopic(); | ||
}); | ||
}); | ||
break; | ||
case COMMANDS.clean_spot: | ||
this.vacuum.spotClean(() => { | ||
this.updateStateTopic(); | ||
}); | ||
break; | ||
case COMMANDS.locate: | ||
this.vacuum.findRobot(() => { | ||
this.updateStateTopic(); | ||
}); | ||
break; | ||
case COMMANDS.start_pause: | ||
this.vacuum.getCurrentStatus((err, res) => { | ||
if(!err) { | ||
if(res.in_cleaning === 1 && [5,11,17].indexOf(res.state) !== -1) { | ||
this.vacuum.pauseCleaning(() => { | ||
this.updateStateTopic(); | ||
}); | ||
} else { | ||
this.vacuum.startCleaning(() => { | ||
this.updateStateTopic(); | ||
}); | ||
} | ||
} | ||
}); | ||
break; | ||
case COMMANDS.set_fan_speed: | ||
this.vacuum.setFanSpeed(FAN_SPEEDS[param], () => { | ||
this.updateStateTopic(); | ||
}); | ||
break; | ||
default: | ||
this.updateStateTopic(); | ||
} | ||
|
||
}; | ||
|
||
module.exports = MqttClient; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
const fs = require("fs"); | ||
const path = require("path"); | ||
|
||
const Tools = { | ||
MK_DIR_PATH : function(filepath) { | ||
var dirname = path.dirname(filepath); | ||
if (!fs.existsSync(dirname)) { | ||
Tools.MK_DIR_PATH(dirname); | ||
} | ||
if (!fs.existsSync(filepath)) { | ||
fs.mkdirSync(filepath); | ||
} | ||
} | ||
}; | ||
|
||
module.exports = Tools; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.