User Tools

Site Tools


Sidebar

Public
Internal
public:it:homeassistant

This is an old revision of the document!


Home Assistant

Self hosted server that allows you to control many different types of IOT devices.

Home Assistant

HestiaPi

Open source thermostat.

https://hestiapi.com/

Espurna

Tasmota

Integration with Home Assistant seems to be in beta and uses MQTT.

Sonoff S31 Commands

$ curl -s http://192.168.30.132/cm?cmnd=power|jq
{
  "POWER": "ON"
}
$ curl -s http://192.168.30.132/cm?cmnd=status|jq
{
  "Status": {
    "Module": 41,
    "DeviceName": "s31-power-2",
    "FriendlyName": [
      "s31-power-2"
    ],
    "Topic": "tasmota_07E0AD",
    "ButtonTopic": "0",
    "Power": 1,
    "PowerOnState": 3,
    "LedState": 1,
    "LedMask": "FFFF",
    "SaveData": 1,
    "SaveState": 1,
    "SwitchTopic": "0",
    "SwitchMode": [
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0
    ],
    "ButtonRetain": 0,
    "SwitchRetain": 0,
    "SensorRetain": 0,
    "PowerRetain": 0
  }
}
$ curl -s http://192.168.30.132/cm?cmnd=Power%20Off
{"POWER":"OFF"}
$ curl -s http://192.168.30.132/cm?cmnd=Power%20On 
{"POWER":"ON"}
$ curl -s http://192.168.30.132/cm?cmnd=FriendlyName%20testing
{"FriendlyName1":"testing"}
$ curl -s http://192.168.30.132/cm?cmnd=Status%200|jq
{
  "Status": {
    "Module": 41,
    "DeviceName": "s31-power-2",
    "FriendlyName": [
      "testing"
    ],
    "Topic": "tasmota_07E0AD",
    "ButtonTopic": "0",
    "Power": 1,
    "PowerOnState": 3,
    "LedState": 1,
    "LedMask": "FFFF",
    "SaveData": 1,
    "SaveState": 1,
    "SwitchTopic": "0",
    "SwitchMode": [
      0,
      0,
      0,
      0,
      0,
      0,
      0,
      0
    ],
    "ButtonRetain": 0,
    "SwitchRetain": 0,
    "SensorRetain": 0,
    "PowerRetain": 0
  },
  "StatusPRM": {
    "Baudrate": 4800,
    "SerialConfig": "8E1",
    "GroupTopic": "tasmotas",
    "OtaUrl": "http://ota.tasmota.com/tasmota/release/tasmota.bin.gz",
    "RestartReason": "Power On",
    "Uptime": "0T00:19:57",
    "StartupUTC": "2021-01-25T21:33:18",
    "Sleep": 50,
    "CfgHolder": 4617,
    "BootCount": 14,
    "BCResetTime": "2021-01-15T02:55:01",
    "SaveCount": 39,
    "SaveAddress": "F8000"
  },
  "StatusFWR": {
    "Version": "9.2.0(tasmota)",
    "BuildDateTime": "2020-12-21T15:03:40",
    "Boot": 31,
    "Core": "2_7_4_9",
    "SDK": "2.2.2-dev(38a443e)",
    "CpuFrequency": 80,
    "Hardware": "ESP8266EX",
    "CR": "400/699"
  },
  "StatusLOG": {
    "SerialLog": 0,
    "WebLog": 2,
    "MqttLog": 2,
    "SysLog": 0,
    "LogHost": "",
    "LogPort": 514,
    "SSId": [
      "PKLAN-IOT",
      ""
    ],
    "TelePeriod": 10,
    "Resolution": "558180C0",
    "SetOption": [
      "00008009",
      "2805C8000100068000005A00000000000000",
      "00000000",
      "00006000",
      "00000000"
    ]
  },
  "StatusMEM": {
    "ProgramSize": 586,
    "Free": 416,
    "Heap": 26,
    "ProgramFlashSize": 1024,
    "FlashSize": 4096,
    "FlashChipId": "1640EF",
    "FlashFrequency": 40,
    "FlashMode": 3,
    "Features": [
      "00000809",
      "8FDAC787",
      "04368001",
      "000000CF",
      "010013C0",
      "C000F981",
      "00004004",
      "00001000"
    ],
    "Drivers": "1,2,3,4,5,6,7,8,9,10,12,16,18,19,20,21,22,24,26,27,29,30,35,37,45",
    "Sensors": "1,2,3,4,5,6"
  },
  "StatusNET": {
    "Hostname": "tasmota_07E0AD-0173",
    "IPAddress": "192.168.30.132",
    "Gateway": "192.168.30.1",
    "Subnetmask": "255.255.255.0",
    "DNSServer": "192.168.1.1",
    "Mac": "C8:2B:96:07:E0:AD",
    "Webserver": 2,
    "WifiConfig": 4,
    "WifiPower": 17
  },
  "StatusMQT": {
    "MqttHost": "192.168.20.207",
    "MqttPort": 1883,
    "MqttClientMask": "DVES_%06X",
    "MqttClient": "DVES_07E0AD",
    "MqttUser": "phil",
    "MqttCount": 0,
    "MAX_PACKET_SIZE": 1200,
    "KEEPALIVE": 30
  },
  "StatusTIM": {
    "UTC": "2021-01-25T21:53:15",
    "Local": "2021-01-25T22:53:15",
    "StartDST": "2021-03-28T02:00:00",
    "EndDST": "2021-10-31T03:00:00",
    "Timezone": "+01:00",
    "Sunrise": "08:28",
    "Sunset": "17:36"
  },
  "StatusPTH": {
    "PowerDelta": [
      0,
      0,
      0
    ],
    "PowerLow": 0,
    "PowerHigh": 0,
    "VoltageLow": 0,
    "VoltageHigh": 0,
    "CurrentLow": 0,
    "CurrentHigh": 0
  },
  "StatusSNS": {
    "Time": "2021-01-25T22:53:15",
    "ENERGY": {
      "TotalStartTime": "2021-01-15T02:55:01",
      "Total": 0,
      "Yesterday": 0,
      "Today": 0,
      "Power": 0,
      "ApparentPower": 0,
      "ReactivePower": 0,
      "Factor": 0,
      "Voltage": 118,
      "Current": 0
    }
  },
  "StatusSTS": {
    "Time": "2021-01-25T22:53:15",
    "Uptime": "0T00:19:57",
    "UptimeSec": 1197,
    "Heap": 26,
    "SleepMode": "Dynamic",
    "Sleep": 50,
    "LoadAvg": 19,
    "MqttCount": 0,
    "POWER": "ON",
    "Wifi": {
      "AP": 1,
      "SSId": "PKLAN-IOT",
      "BSSId": "02:9F:C2:77:2D:37",
      "Channel": 11,
      "RSSI": 100,
      "Signal": -43,
      "LinkCount": 1,
      "Downtime": "0T00:00:03"
    }
  }
}
$ curl -s http://192.168.30.136/cm?cmnd=Status%208|jq
{
  "StatusSNS": {
    "Time": "2021-01-25T22:56:32",
    "ENERGY": {
      "TotalStartTime": "2021-01-15T00:21:03",
      "Total": 48.545,
      "Yesterday": 4.492,
      "Today": 5.049,
      "Power": 380,
      "ApparentPower": 384,
      "ReactivePower": 56,
      "Factor": 0.99,
      "Voltage": 120,
      "Current": 3.2
    }
  }
}

Just in case I'm saving this.

import requests
import json

class s31powerplug:

  def __init__(self, target):
    self.target = target

  def cmd(self, cmd):
    r = requests.get('http://%s/cm?cmnd=%s' % (self.target, cmd))
    if r.status_code == 200:
      return r.json()
    else:
      return False


  def energy(self):
    r = self.cmd('Status%208')
    return r['StatusSNS']['ENERGY']


  def network(self):
    r = self.cmd('Status%205')
    return r['StatusNET']


  def power(self, toggle=None):
    if toggle is None:
      return self.cmd('power')

    elif toggle:
      return self.cmd('power%20On')

    else:
      return self.cmd('power%20Off')

MQTT

Notes from Tom

if you enable websocket interface on mosquitto, you can also talk to it from a browser using javascript, which is kinda handy. Here's the lib I've used for that → https://github.com/mqttjs/MQTT.js (basically it just encapsulates the normal MQTT protocol inside a websocket connection so that it can be used directly in a browser – it's handy for things like dashboards that update in real-time)

I've just used curl with the API so far (from shell scripts) well, plus the MQTT interface via. a python library this one → https://pypi.org/project/paho-mqtt/

that's an example of a simple MQTT frontend – I kinda cheated by doing some server-side stuff in PHP, so I provided both the PHP source as well as the final HTML it generates I wrote that back in 2016, but I think it should still work with modern servers/libraries lol some of this code is kinda gross, but at least it gives you the general idea

relay_control.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>MCP Relay Power Control</title>
<link rel="shortcut icon" href="../favicon-power.png" type="image/png" />
<meta name="viewport" content="initial-scale = 0.5, maximum-scale = 1.0, minimum-scale = 0.5" />
<style type="text/css">@import "style.css";</style>
</head>
<body>
<script src="../mqttws31.js" type="text/javascript"></script>
<script type="text/javascript">
mqtt_topic = "power/relay";

function mqtt_connect() {
  console.log("MQTT connecting...");
  client = new Paho.MQTT.Client('mqtt.mcp.lcl', 8000, "Web interface for computer power control from 192.168.48.217 started at Mon, 25 Jan 2021 18:45:22 -0600");
  client.onConnectionLost = on_mqtt_connection_lost;
  client.onMessageArrived = on_mqtt_message;
  client.connect({onSuccess:on_mqtt_connect});
}

mqtt_connect();

function on_mqtt_connect() {
  console.log("MQTT connected.");
  client.subscribe(mqtt_topic + "/#");
};
function on_mqtt_connection_lost(response) {
  if (response.errorCode !== 0) {
    console.log("MQTT connection lost: " + response.errorMessage);
  }
  update_online(false);
  console.log("MQTT attempting reconnect...");
  mqtt_connect();
};
function on_mqtt_message(msg) {
  console.log("MQTT received: " + msg.destinationName + " => " + msg.payloadString);
  if (msg.destinationName.indexOf(mqtt_topic) == 0) {
    var short_topic = msg.destinationName.substr(mqtt_topic.length + 1);
    if (short_topic == "status") {
      switch (msg.payloadString) {
        case "online":
          update_online(true);
          break;
        case "offline":
          update_online(false);
          break;
        default:
          console.log("WARNING: Invalid status received: " + msg.payloadString);
      }
    } else {
      var element = document.getElementById(short_topic);
      if (element) {
        update_element(short_topic, msg.payloadString, element);
      } else {
        console.log("INFO: Ignored MQTT message for unlisted computer: " + short_topic + " => " + msg.payloadString);
      }
    }
  } else {
    console.log("WARNING: Unrecognized MQTT message received: " + short_topic + " => " + msg.payloadString);
  }
  //client.disconnect();
};
function send_mqtt(device, state) {
  if (document.getElementById("relays").className == "online") {
    if (state == "off" && ! confirm("Are you sure you want to power off " + device + "?")) {
      return;
    }
    if (state == "on" && ! confirm("Are you sure you want to power on " + device + "?")) {
      return;
    }
    console.log("Sending MQTT: " + device + " => " + state);
    var msg = new Paho.MQTT.Message(String(state));
    msg.destinationName = mqtt_topic + "/" + String(device);
    msg.qos = 1;
    msg.retained = true;
    client.send(msg);
  } else {
    console.log("Ignoring command while relay power controller is offline");
  }
};
function update_online(is_online) {
  if (is_online) {
    console.log("Marking display online");
    document.getElementById("relays").className = "online";
  } else {
    console.log("Marking display offline");
    document.getElementById("relays").className = "offline";
  }
};
function update_element(device, status, element) {
  console.log("Marking status of device " + device + " as " + status);
  switch (status) {
    case "0":
      element.className = "off";
      break;
    case "1":
      element.className = "on";
      break;
    case "off":
    case "on":
      element.className = "pending";
      break;
    default:
      element.className = "";
  }
};
function toggle_device(device) {
  state = document.getElementById(device).className;
  switch (state) {
    case "off":
      return send_mqtt(device, "on");
    case "on":
      return send_mqtt(device, "off");
    default:
      console.log("Not known how to toggle state " + state + " on device " + device);
  }
}
</script>
<h1>MCP Relay Power Control</h1>
<div id="relays" class="offline">
<div class="buttonrow"><div class="button"><a id="soffit_n" href="javascript:toggle_device('soffit_n');">soffit_n</a></div><div class="button"><a id="soffit_s" href="javascript:toggle_device('soffit_s');">soffit_s</a></div><div class="button"><a id="vest_r" href="javascript:toggle_device('vest_r');">vest_r</a></div><div class="button"><a id="vest_w" href="javascript:toggle_device('vest_w');">vest_w</a></div><div class="button"><a id="console" href="javascript:toggle_device('console');">console</a></div><div class="button"><a id="cat_main" href="javascript:toggle_device('cat_main');">cat_main</a></div><div class="button"><a id="cat_rope" href="javascript:toggle_device('cat_rope');">cat_rope</a></div><div class="button"><a id="inuse" href="javascript:toggle_device('inuse');">inuse</a></div></div><div class="buttonrow"><div class="button"><a id="ds-proj-a" href="javascript:toggle_device('ds-proj-a');">ds-proj-a</a></div><div class="button"><a id="ds-proj-b" href="javascript:toggle_device('ds-proj-b');">ds-proj-b</a></div><div class="button"><a id="ds-proj-c" href="javascript:toggle_device('ds-proj-c');">ds-proj-c</a></div><div class="button"><a id="ds-proj-d" href="javascript:toggle_device('ds-proj-d');">ds-proj-d</a></div><div class="button"><a id="ds-proj-e" href="javascript:toggle_device('ds-proj-e');">ds-proj-e</a></div><div class="button"><a id="ds-proj-f" href="javascript:toggle_device('ds-proj-f');">ds-proj-f</a></div><div class="button"><a id="giftshop" href="javascript:toggle_device('giftshop');">giftshop</a></div><div class="button"><a id="waiting-sound" href="javascript:toggle_device('waiting-sound');">waiting-sound</a></div></div><div class="buttonrow"><div class="button"><a id="waiting" href="javascript:toggle_device('waiting');">waiting</a></div><div class="button"><a id="office-sound" href="javascript:toggle_device('office-sound');">office-sound</a></div><div class="button"><a id="epson-proj" href="javascript:toggle_device('epson-proj');">epson-proj</a></div><div class="button"><a id="waiting-proj" href="javascript:toggle_device('waiting-proj');">waiting-proj</a></div></div></div>

</body>
</html>

relay_control.php

<?php

require 'power.inc.php';

_read_devices_csv();

?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>MCP Relay Power Control</title>
<link rel="shortcut icon" href="../favicon-power.png" type="image/png" />
<meta name="viewport" content="initial-scale = 0.5, maximum-scale = 1.0, minimum-scale = 0.5" />
<style type="text/css">@import "style.css";</style>
</head>
<body>
<script src="../mqttws31.js" type="text/javascript"></script>
<script type="text/javascript">
mqtt_topic = "<?php echo MQTT_TOPIC; ?>";

function mqtt_connect() {
  console.log("MQTT connecting...");
  client = new Paho.MQTT.Client('mqtt.mcp.lcl', 8000, "Web interface for computer power control from <?php echo $_SERVER['REMOTE_ADDR'] ?> started at <?php echo date('r'); ?>");
  client.onConnectionLost = on_mqtt_connection_lost;
  client.onMessageArrived = on_mqtt_message;
  client.connect({onSuccess:on_mqtt_connect});
}

mqtt_connect();

function on_mqtt_connect() {
  console.log("MQTT connected.");
  client.subscribe(mqtt_topic + "/#");
};
function on_mqtt_connection_lost(response) {
  if (response.errorCode !== 0) {
    console.log("MQTT connection lost: " + response.errorMessage);
  }
  update_online(false);
  console.log("MQTT attempting reconnect...");
  mqtt_connect();
};
function on_mqtt_message(msg) {
  console.log("MQTT received: " + msg.destinationName + " => " + msg.payloadString);
  if (msg.destinationName.indexOf(mqtt_topic) == 0) {
    var short_topic = msg.destinationName.substr(mqtt_topic.length + 1);
    if (short_topic == "status") {
      switch (msg.payloadString) {
        case "online":
          update_online(true);
          break;
        case "offline":
          update_online(false);
          break;
        default:
          console.log("WARNING: Invalid status received: " + msg.payloadString);
      }
    } else {
      var element = document.getElementById(short_topic);
      if (element) {
        update_element(short_topic, msg.payloadString, element);
      } else {
        console.log("INFO: Ignored MQTT message for unlisted computer: " + short_topic + " => " + msg.payloadString);
      }
    }
  } else {
    console.log("WARNING: Unrecognized MQTT message received: " + short_topic + " => " + msg.payloadString);
  }
  //client.disconnect();
};
function send_mqtt(device, state) {
  if (document.getElementById("relays").className == "online") {
    if (state == "off" && ! confirm("Are you sure you want to power off " + device + "?")) {
      return;
    }
    if (state == "on" && ! confirm("Are you sure you want to power on " + device + "?")) {
      return;
    }
    console.log("Sending MQTT: " + device + " => " + state);
    var msg = new Paho.MQTT.Message(String(state));
    msg.destinationName = mqtt_topic + "/" + String(device);
    msg.qos = 1;
    msg.retained = true;
    client.send(msg);
  } else {
    console.log("Ignoring command while relay power controller is offline");
  }
};
function update_online(is_online) {
  if (is_online) {
    console.log("Marking display online");
    document.getElementById("relays").className = "online";
  } else {
    console.log("Marking display offline");
    document.getElementById("relays").className = "offline";
  }
};
function update_element(device, status, element) {
  console.log("Marking status of device " + device + " as " + status);
  switch (status) {
    case "0":
      element.className = "off";
      break;
    case "1":
      element.className = "on";
      break;
    case "off":
    case "on":
      element.className = "pending";
      break;
    default:
      element.className = "";
  }
};
function toggle_device(device) {
  state = document.getElementById(device).className;
  switch (state) {
    case "off":
      return send_mqtt(device, "on");
    case "on":
      return send_mqtt(device, "off");
    default:
      console.log("Not known how to toggle state " + state + " on device " + device);
  }
}
</script>
<h1>MCP Relay Power Control</h1>
<div id="relays" class="offline">
<?php

function print_device($device, $params) {
  print '<div class="button"><a id="'. $device .'" href="javascript:toggle_device(\''. $device .'\');">'. $device .'</a></div>';
}

print '<div class="buttonrow">';
$i = 0;
foreach ($devices as $device => $params) {
  print_device($device, $params);
  if (++$i == 8) {
    print '</div><div class="buttonrow">';
    $i = 0;
  }
}
print '</div>';

?></div>

</body>
</html>

Gear

Misc

public/it/homeassistant.1641147542.txt.gz · Last modified: 2022/01/02 12:19 by phil