Mcclellan

From i3Detroit
Jump to: navigation, search
Mcclellan
WeirdFantasy17ThereWillComeSoftRainsWallyWood565.jpg
Name mcclellan
Zone Infrastructure


Owner i3Detroit
Make Model Debian VM
Part Number
Date Acquired 2015-08-09
Storage Location hardac.i3detroit.local
Authorization Required Yes
Status Running
Value 0
IP Address 10.13.0.26
MAC Address 08:00:27:7e:08:1e
Hostname mcclellan
Documentation OpenHAB

Mosquitto

Other References Supersedes:


Intro

This VM serves space automation functions. Currently, discussion is about two applications:

  • Smarter thermal control, with furnaces, AC, and fans controlled synchronously
  • Better power reporting from the Power Meter

Rules

Instructions

Maintenance Info

FAQ

ToDo

  • IoT Subnet
* Wifi IoT network connected to IoT DHCP

Authorized Users and Trainers

Trainer Name Certified Date
Amelia Meyer 2016-11-25
Evan Allen 2016-11-25
Leonard Kinnaird-Heether 2016-11-25
Mark Furland 2016-11-27
User Name Authorized By Date of Most Recent Training
Amelia Meyer Amelia Meyer 2016-11-25
Evan Allen Amelia Meyer 2016-11-25
Leonard Kinnaird-Heether Evan Allen 2016-11-25
Mark Furland Amelia Meyer 2016-11-27


Mcclellan Zone: Infrastructure https://wiki.pumpingstationone.org/images/Authorization_required.svg "/> https://www.i3detroit.org/wiki/Mcclellan

Services

OpenHAB2 runtime

Port 8080

To make config changes, there *might* be a openahb console command, but it didn't work. Restart the daemon.

To restart the daemon: `sudo service openhab2 restart`

To connect to the openhab 2 console: `ssh openhab@localhost -p 8101` password `habopen`. Those are the defaults. Not accessible from non-localhost.

Mosquitto MQTT broker

  • Port 1883

Listen to all: `mosquitto_sub -v -h localhost -p 1883 -t '#'`

Services that have yet to be reinstalled

Slack integration

Modified slackhab.py to work with new Slack RTM API
from __future__ import print_function
from __future__ import unicode_literals
import requests
import time
import xml.etree.ElementTree as xml
from rtmbot.core import Plugin

crontable = []
outputs = []

debug            = True

openhab_url      = 'http://127.0.0.1:8080'
slackhab_user_id = "<<<elided>>>"

headers          = { 'Content-Type': 'text/plain' }

class SlackHab(Plugin):

    def process_message(self,data):
        self.print_debug(str(data))

        # check we have sufficient details
        if 'channel' not in data or 'user' not in data or 'text' not in data:
            return

        channel = data['channel']
        user = data['user']
        text = data['text']

        # first check if we are interested in this command
        command_text = self.get_command_text(channel, user, text)

        if command_text is None:
            self.print_debug('Boring message')
            return

        tokens = command_text.split()
        if len(tokens) == 0:
            self.print_debug('No tokens')
            return

        command = tokens[0].lower()

        if command == "send" and len(tokens) >= 3:
            item = tokens[1]
            value = " ".join(tokens[2:])
            url = openhab_url + '/rest/items/' + item
            r = requests.post(url, headers=headers, data=value)

            if self.check_response(r, channel):
                self.outputs.append([ channel, "```Sent %s command to %s```" % (value, item) ])

        elif command == "update" and len(tokens) >= 3:
            item = tokens[1]
            value = " ".join(tokens[2:])
            url = openhab_url + '/rest/items/' + item + '/state'
            r = requests.put(url, headers=headers, data=value)

            if self.check_response(r, channel):
               self.outputs.append([ channel, "```Sent %s update to %s```" % (value, item) ])

        elif command == "status" and len(tokens) >= 2:
            item = tokens[1]
            url = openhab_url + '/rest/items/' + item + '/state'
            r = requests.get(url, headers=headers)

            if self.check_response(r, channel):
                self.outputs.append([ channel, "```%s is %s```" % (item, r.text) ])

        elif command == "items":
            filter = None
            if len(tokens) > 1:
                filter = tokens[1].lower()

            url = openhab_url + '/rest/items'
            r = requests.get(url, headers=headers)

            if self.check_response(r, channel):
                items = []
                output = ""
                maxtypelen = 0
                maxnamelen = 0

                for item in xml.fromstring(r.content).findall('item'):
                    name = item.find('name').text
                    type = item.find('type').text
                    if filter is None or filter in name.lower():
                        items.append(item)
                        if len(type) > maxtypelen:
                            maxtypelen = len(type)
                        if len(name) > maxnamelen:
                            maxnamelen = len(name)

                for item in items:
                    name  = item.find('name').text
                    state = item.find('state').text
                    type  = item.find('type').text
                    output = output + "%s%s%s\n" % (type.ljust(maxtypelen+5), name.ljust(maxnamelen+5), state)
                    if len(output) >= 8000:
                        output = output + "... (too much output, please specify a filter)"
                        break

                if len(items) == 0:
                    if filter is None:
                        self.outputs.append([ channel, "```No items found```" ])
                    else:
                        self.outputs.append([ channel, "```No items found matching '%s'```" % (filter) ])
                else:
                    self.outputs.append([ channel, "```%s```" % (output) ])

    def get_command_text(self,channel, user, text):
        if channel == "" or channel is None:
            self.print_debug('No channel')
            return None
        if user == "" or user is None:
            self.print_debug('No user')
            return None
        if text == "" or text is None:
            self.print_debug('No text')
            return None

        # check for a message directed at our bot
        user_tag = "<@%s>" % (slackhab_user_id)
        self.print_debug('Calculated user tag as %s'%user_tag)

        if text.startswith(user_tag):
            self.print_debug('Returning text from command in channel')
            return text[len(user_tag):]

        # check for a DM to our bot
        if channel.startswith("D"):
            self.print_debug('Returning text from command in DM')
            return text
        self.print_debug('No DM or channel command')
        return None

    def check_response(self,r, channel):
        # check our rest api call was successful
        if r.status_code == 200:
            return True
        if r.status_code == 201:
            return True

        # log the response code/reason back to our slack channel
        self.outputs.append([ channel, "```%d: %s```" % (r.status_code, r.reason) ])
        return False

    def print_debug(self,message):
        if debug:
            print(message)
rtmbot.conf
DEBUG: False
SLACK_TOKEN: "<<<elided>>>"
BASE_PATH: "/var/lib/openhab/rtmbot"
ACTIVE_PLUGINS:
    - plugins.slackhab.SlackHab
Systemd service
[Unit]
Description=OpenHAB Slack Bot
After=syslog.target network.target
Requires=openhab.service

[Service]
Type=simple
User=openhab
Group=openhab
WorkingDirectory=/var/lib/openhab/rtmbot
ExecStart=/usr/local/bin/rtmbot -c /var/lib/openhab/rtmbot/rtmbot.conf

[Install]
WantedBy=multi-user.target