Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Swing, Powerful Mode, removed mode change bug #22

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,68 @@ Once authenticated, the list of devices is pulled down exposed to HA using MQTT
1. Show debug messages to help with troubleshooting
2. The MQTT discovery prefix is hard coded to "homeassisstant", this should be configurable on the node.
3. Follow coding standards and best practices

NOTE: Home Assistant HVAC don't have powerful mode option, so using option heat instead of that, setting climate.hvac to heat will turn on powerful mode in the AC.

For UI use HACS library [simple thermostat](https://github.com/nervetattoo/simple-thermostat) and make a card using below yaml code

```yaml
type: custom:simple-thermostat
entity: climate.panasonic_ac
layout:
mode:
headings: false
icons: true
names: true
step_size: '1'
control:
hvac:
auto:
name: false
cool:
name: false
dry:
name: false
fan_only:
name: false
heat:
name: false
icon: mdi:snowflake-variant
'off':
name: false
fan:
auto:
icon: mdi:fan-auto
name: false
low:
icon: mdi:fan-speed-1
name: false
medium:
icon: mdi:fan-speed-2
name: false
high:
icon: mdi:fan-speed-3
name: false
swing:
'0':
icon: mdi:autorenew
name: false
'1':
icon: mdi:arrow-left-thin
name: false
'2':
icon: mdi:arrow-bottom-left-thin
name: false
'3':
icon: mdi:arrow-down-thin
name: false
'4':
icon: mdi:arrow-bottom-right-thin
name: false
'5':
icon: mdi:arrow-right-thin
name: false

```

<img width="428" alt="ac_ui" src="https://user-images.githubusercontent.com/93876251/151554889-ab9bd367-d1de-465f-9f20-c05e39be0f23.png">
14 changes: 8 additions & 6 deletions api/miraie.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,17 @@ const parseHomeDetails = response => {
id: d.deviceId,
name: deviceName,
friendlyName: d.deviceName,
modeStatus : '',
controlTopic: d.topic ? `${d.topic[0]}/control` : null,
statusTopic: d.topic ? `${d.topic[0]}/status` : null,
connectionStatusTopic: d.topic ? `${d.topic[0]}/connectionStatus` : null,
haStatusTopic: `miraie-ac/${deviceName}/state`,
haAvailabilityTopic: `miraie-ac/${deviceName}/availability`,
haActionTopic: `miraie-ac/${deviceName}/action`,
haCommandTopic: `miraie-ac/${deviceName}/+/set`,
haMonthlyPwrTopic: `miraie-ac/${deviceName}/monthly-power-consumption/state`,
haDailyPwrTopic: `miraie-ac/${deviceName}/daily-power-consumption/state`
haStatusTopic: `/ac/${deviceName}/status`,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need to change the topics? It will be breaking change.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to change the topic, i changed topic for my own requirements, however there is some topic added for mode settings, change that as needed

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haModeTopic in miraie.js, mode_stat_t and cmd_t in discovery.js and other changes related to this mode settings in other files.
you can keep miraie-ac no need to change to /ac
note: action mqtt and related code is removed, since home assistant action supported are cooling, heating, idle and off, and its not of much use

haAvailabilityTopic: `/ac/${deviceName}/availability`,
haActionTopic: `/ac/${deviceName}/action`,
haCommandTopic: `/ac/${deviceName}/+/set`,
haModeTopic: `/ac/${deviceName}/mode/update`,
haMonthlyPwrTopic: `/ac/${deviceName}/monthly-power-consumption/state`,
haDailyPwrTopic: `/ac/${deviceName}/daily-power-consumption/state`
};

return device;
Expand Down
2 changes: 1 addition & 1 deletion broker/broker-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const onMiraieStateChanged = function (topic, payload) {
};

const onHACommandReceieved = function (topic, payload) {
const device = _devices.find(d => topic.startsWith(`miraie-ac/${d.name}/`));
const device = _devices.find(d => topic.startsWith(`/ac/${d.name}/`));
if (device) {
Logger.logDebug(`Received update from HA for ${device.friendlyName}.`);
_miraieBroker.publish(device, payload.toString(), topic);
Expand Down
18 changes: 17 additions & 1 deletion broker/ha-broker.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ const generateAvailabilityMessage = device => {
};

const generateStateMessages = device => {
let mode = device.status.acmd;
if(device.status.ps == 'off'){
mode = 'off';
}else if(device.status.acpm == "on"){
mode = "heat";
}else if(device.status.acmd == "fan"){
mode = "fan_only";
}
device.modeStatus = mode;
Logger.logDebug(`Power :${device.status.ps} , Mode: ${device.modeStatus}`);

const modeMsg = {
topic: device.haModeTopic,
payload: mode
};

const actionMsg = {
topic: device.haActionTopic,
payload: getAction(device.status)
Expand All @@ -91,7 +107,7 @@ const generateStateMessages = device => {
payload: device.consumption.daily.toString()
}

return [actionMsg, statusMsg, monthlyPowerConsMsg, dailyPowerConsMsg];
return [modeMsg, statusMsg, monthlyPowerConsMsg, dailyPowerConsMsg]; //actionmsg removed
};

module.exports = HABroker;
Expand Down
116 changes: 94 additions & 22 deletions broker/miraie-broker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ let onStateChangedCallback;
const CMD_TYPES = {
MODE: 'mode',
TEMPERATURE: 'temp',
FAN: 'fan'
FAN: 'fan',
SWING: 'swing'
};

const brokerDetails = {
Expand Down Expand Up @@ -52,29 +53,87 @@ const getCommandType = topic => {
if (topic.endsWith('/fan/set')) {
return CMD_TYPES.FAN;
}

if (topic.endsWith('/swing/set')) {
return CMD_TYPES.SWING;
}
};

const generateModeMessages = (basePayload, command, topic) => {
const powerMode = command == 'off' ? 'off' : 'on';
const acMode = command == 'fan_only' ? 'fan' : command;
const generateModeMessages = (basePayload, command, topic, device) => {
if(command == "fan_only"){
command = "fan";
}
let powerMsg;
if(command == "off"){
powerMsg = {
topic,
payload: {
...basePayload,
ps: "off"
}
};
return [powerMsg];
}else{
powerMsg = {
topic,
payload: {
...basePayload,
ps: "on"
}
};

if(command == "heat"){
const modeMessage = {
topic,
payload: {
...basePayload,
acmd: "cool"
}
};
const powerfulMessage = {
topic,
payload: {
...basePayload,
acpm: "on"
}
};
if(device.status.ps == "off"){
return [powerMsg, modeMessage, powerfulMessage];
}else{
if(device.modeStatus == "cool"){
return [powerfulMessage];
}else{
return [modeMessage, powerfulMessage];
}
}

const powerMessage = {
topic,
payload: {
...basePayload,
ps: powerMode
}
};
}else{
const modeMessage = {
topic,
payload: {
...basePayload,
acmd: command
}
};
if(device.status.ps == "off"){
return [powerMsg, modeMessage];
}else{
if(device.status.acpm == "on" && command == "cool"){
const powerfulMessage = {
topic,
payload: {
...basePayload,
acpm: "off"
}
};
return [powerfulMessage];
}else{
return [modeMessage];
}
}

const modeMessage = {
topic,
payload: {
...basePayload,
acmd: acMode
}
};

return [powerMessage, modeMessage];
}
};

const generateTemperatureMessage = (basePayload, command, topic) => {
Expand All @@ -101,14 +160,27 @@ const generateFanMessage = (basePayload, command, topic) => {
];
};

const generateMessages = (topic, command, cmdType, basePayload) => {
const generateSwingMessage = (basePayload, command, topic) => {
return [{
topic,
payload: {
...basePayload,
acvs: parseInt(command)
}
}];
};

const generateMessages = (device, command, cmdType, basePayload) => {
let topic = device.controlTopic;
switch (cmdType) {
case CMD_TYPES.MODE:
return generateModeMessages(basePayload, command.toLowerCase(), topic);
return generateModeMessages(basePayload, command.toLowerCase(), topic, device);
case CMD_TYPES.TEMPERATURE:
return generateTemperatureMessage(basePayload, command.toLowerCase(), topic);
case CMD_TYPES.FAN:
return generateFanMessage(basePayload, command.toLowerCase(), topic);
case CMD_TYPES.SWING:
return generateSwingMessage(basePayload, command.toLowerCase(), topic);
}
return [];
};
Expand All @@ -132,7 +204,7 @@ MiraieBroker.prototype.connect = function (username, password) {
MiraieBroker.prototype.publish = function (device, command, commandTopic) {
const basePayload = buildBasePayload(device);
const cmdType = getCommandType(commandTopic);
const messages = generateMessages(device.controlTopic, command, cmdType, basePayload);
const messages = generateMessages(device, command, cmdType, basePayload);
messages.map(m => {
mqttClient.publish(m.topic, m.payload, 0, false, onPublishCompleted);
});
Expand Down
38 changes: 22 additions & 16 deletions mqtt/mqtt-discovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,20 @@ module.exports = MqttDiscovery;

const generateConfigPayload = device => {
const deviceName = device.name;
const stateTopic = `miraie-ac/${deviceName}/state`;
const stateTopic = `/ac/${deviceName}/status`;

const discoMsg = {
icon: 'mdi:air-conditioner',
name: device.friendlyName,
unique_id: deviceName,
mode_cmd_t: `miraie-ac/${deviceName}/mode/set`,
mode_stat_t: stateTopic,
mode_stat_tpl:
"{% set mode = value_json.acmd %}{% set power = value_json.ps %}{%- if power == 'off' -%} off {%- else -%} {{ 'fan_only' if mode == 'fan' else mode }} {%- endif -%}",
avty_t: `miraie-ac/${deviceName}/availability`,
mode_cmd_t: `/ac/${deviceName}/mode/set`,
mode_stat_t: `/ac/${deviceName}/mode/update`,

avty_t: `/ac/${deviceName}/availability`,
pl_avail: 'online',
pl_not_avail: 'offline',

temp_cmd_t: `miraie-ac/${deviceName}/temp/set`,
temp_cmd_t: `/ac/${deviceName}/temp/set`,
temp_stat_t: stateTopic,
temp_stat_tpl: '{{ value_json.actmp }}',

Expand All @@ -26,15 +25,22 @@ const generateConfigPayload = device => {
max_temp: '30',
min_temp: '16',

act_t: `miraie-ac/${deviceName}/action`,
pow_cmd_t: `miraie-ac/${deviceName}/power/set`,
//act_t: `/ac/${deviceName}/action`,
pow_cmd_t: `/ac/${deviceName}/power/set`,

fan_mode_cmd_t: `miraie-ac/${deviceName}/fan/set`,
fan_mode_cmd_t: `/ac/${deviceName}/fan/set`,
fan_mode_stat_t: stateTopic,
fan_mode_stat_tpl: '{{ value_json.acfs }}',

modes: ['auto', 'cool', 'dry', 'fan_only', 'off'],
fan_modes: ['auto', 'quiet', 'low', 'medium', 'high'],
swing_mode_cmd_t: `/ac/${deviceName}/swing/set`, //ha response on swing change
swing_mode_stat_t: stateTopic, //ha set swing
swing_mode_stat_tpl: "{{ value_json.acvs }}",

modes: ['auto', 'cool', 'heat', 'dry', 'fan_only', 'off'], //heat is used for powerful mode
fan_modes: ['auto', 'low', 'medium', 'high'],
swing_modes: ["0", "1", "2", "3", "4", "5"],
temperature_unit: "C",
temp_step: 1,

dev: {
ids: [device.id, device.details.macAddress],
Expand All @@ -50,12 +56,12 @@ const generateConfigPayload = device => {

const generateMonthlyPowerConsumptionPayload = device => {
const deviceName = device.name;
const stateTopic = `miraie-ac/${deviceName}/monthly-power-consumption/state`;
const stateTopic = `/ac/${deviceName}/monthly-power-consumption/state`;

const discoMsg = {
name: `Monthly Power Consumption - ${device.friendlyName}`,
unique_id: `monthly-power-consumption-${deviceName}`,
avty_t: `miraie-ac/${deviceName}/availability`,
avty_t: `/ac/${deviceName}/availability`,
pl_avail: 'online',
pl_not_avail: 'offline',
unit_of_meas: 'kWh',
Expand All @@ -78,12 +84,12 @@ const generateMonthlyPowerConsumptionPayload = device => {

const generateDailyPowerConsumptionPayload = device => {
const deviceName = device.name;
const stateTopic = `miraie-ac/${deviceName}/daily-power-consumption/state`;
const stateTopic = `/ac/${deviceName}/daily-power-consumption/state`;

const discoMsg = {
name: `Daily Power Consumption - ${device.friendlyName}`,
unique_id: `daily-power-consumption-${deviceName}`,
avty_t: `miraie-ac/${deviceName}/availability`,
avty_t: `/ac/${deviceName}/availability`,
pl_avail: 'online',
pl_not_avail: 'offline',
unit_of_meas: 'kWh',
Expand Down