Omaha Carpet Cleaning

Posted Leave a comment

I do web hosting for different companies with Reiners Cloud Consulting LLC which can be found here. If you’re looking for website setup, hosting, or anything let me know.

If you are located within the Omaha Metropolitan Area, I’d love to recommend a good friend of mine Wes Waltermeier, at Action Flooring and Carpet Cleaning to handle all of your flooring maintenance needs. Action Flooring and Carpet Cleaning has been in business since 2002!

Just a few of the services they offer:

  • Carpet Cleaning and stain removal.
  • Home and Commercial carpet cleaning services.
  • Tile and grout cleaning
  • Stairway carpet stretching and installation.
  • Professional carpet installation.

If you’d like a quote, please call 402-740-5700, or use the contact form, on his website here.

Come see why he has so many great 5 star reviews!

Yelp reviews

Facebook reviews


If you are looking for affordable web hosting services, please give me a call. I’d love to take over hosting for you. I use multiple cloud platforms, including Google Cloud Platform, Digital Ocean and Amazon Web Services. Reiners Cloud Consulting LLC

How do I clean messages out of a rocketchat room or channel?

Posted Leave a comment

Trimming RocketChat

This functionality was added to newer versions of rocketchat, this same way WILL work, but it’s easier to do it in the room interface.

We switched from a paid slack account last year, to rocketchat.

I’ve written bots in the past to alert coworkers of system issues in a more public place, but some of my rooms were getting upwards of 10,000 messages and the browser and phones would be extremely slow pulling the room up as message counts were growing.

Sending messages to a chat in a controlled manor is a great way to alert a lot of people to issues, or log something. This should make it super easy to clean the rooms out when they grow larger than you thought they would!

python to the rescue!

My client can do the following:

  1. test connection to server (–whoami)
  2. send a message to a user. (–send –user justin –text “hi there!”)
  3. send a message to a group. (–send –group groupname –text “Hi there!”)
  4. send a message to a channel. (–send –channel channelname –text “Hi there!”
  5. delete all messages in a group. (–delete –group roomname –iknow)
  6. delete all messages in a channel. (–delete –channel roomname –iknow)
  7. install saved rocketchat credentials. (–install –rcuser user –rcpass pass –rchost hostname)
  8. spam a group with test messages (–trash –iknow –group groupname)
  9. spam a channel with test messages (–trash –iknow –channel channelname)

What are these groups and channels?

On rocketchat it gets a little confusing sometimes. If you have a room, where everyone is allowed to view and post, it’s considered a “channel”.

If you have a private channel, it’s considered a “group”.

Cosmicray-rocketchat

I found a newer api, as my last client was using rocket-python, which didnt seem to allow me to delete messages in a somewhat controlled manor.

The api can be installed like so

[code]
python -m pip install cosmicray-rocketchat
[/code]

to use the software paste the following in a file, name it rc-client.py

you might want to install python3:

it’s in the repo for centos, and fedora, and pretty much any operating system, since I use rpm based distros, these instructions are for CentOS.

[code]
sudo yum install python3 pip3
[/code]

[code]
#!/usr/bin/python3

import rocketchat
import argparse
import datetime

parser = argparse.ArgumentParser()
parser.add_argument(‘–rcuser’, help=’The username used with rocketchat, Only needs to be set once.’)
parser.add_argument(‘–rcpass’, help=’The password used with rocketchat. Only needs to be set once.’)
parser.add_argument(‘–rchost’, help=’Chat host to use for API access’)
parser.add_argument(‘–install’, help=’create config file on this machine for access, pass –rcuser (user@domain.com) –rcpass (rcpassword) and –rchost http://chat.domain.com’,action=’store_true’)
parser.add_argument(‘–channel’, help=’channel to send to/operate on’)
parser.add_argument(‘–group’, help=’group to send to/operate on’)
parser.add_argument(‘–user’, help=’user to send to/operate on’)
parser.add_argument(‘–whoami’, help=’test of connection to rocketchat api’, action=’store_true’)
parser.add_argument(‘–delete’, help=’delete messages from group or channel’, action=’store_true’)
parser.add_argument(‘–verbose’, help=’enable more logging to console’)
parser.add_argument(‘–send’, help=’text to send to room, user, or channel’, action=’store_true’)
parser.add_argument(‘–iknow’, help=’required for deletion of messages.’, action=’store_true’)
parser.add_argument(‘–text’, help=’text to send to room, user, or channel’)
parser.add_argument(‘–trash’,help=’user with –iknow to spam a room with messages, mainly used for testing’, action=’store_true’)
args = parser.parse_args()

#store variables
whoami = args.whoami
text = args.text
user = args.user
group = args.group
channel = args.channel
sendmsg = args.send
install = args.install
rcuser = args.rcuser
rcpass = args.rcpass
rchost = args.rchost
verbose = args.verbose
iknow = args.iknow
delete = args.delete
now = datetime.datetime.now()
trash = args.trash

#first setup, creates local file with config data defaults.
if install == True:
if rcuser != None:
if rcpass != None:
if rchost != None:
rocketchat.create_creds_file(rcuser,rcpass)
rocketchat.configure(domain=rchost)
if verbose == True:
print(“storing config”)
rocketchat.store_config()

#prints basic info about logged in bot user, used to test config
if whoami == True:
print(rocketchat.models.User.me)

#send message code
if sendmsg == True:
if channel != None:
if text != None:
myroom = rocketchat.channels()[channel]
myroom.send(text)
if user != None:
if text != None:
users = rocketchat.users()
foo = users[user]
foo.send(text)
#users[user].send(text)
if group != None:
if text != None:
mygroup = rocketchat.groups()[group]
mygroup.send(text)

#channel cleaning
if iknow == True:
if delete == True:
if channel != None:
while True:
try:
myroom = rocketchat.channels()[channel]
message = myroom.messages.last[0]
message.delete()
except:
myroom.send(“Room cleaned: ” + str(now))
break

    if group != None:
        while True:
            try:
                myroom = rocketchat.groups()[group]
                message = myroom.messages.last[0]
                message.delete()
            except:
                myroom.send("Room cleaned: " + str(now) )
                break

#room trashers for testing deletes
if trash == True:
if channel != None:
if iknow == True:
count = 0
mychannel = rocketchat.channels()[channel]
while True:
print(count)
mychannel.send(‘testmessage ‘ + str(count))
count += 1
if count == 3000:
mychannel.send(‘room successfully trashed’)
break

if group != None:
    if iknow == True:
        count = 0
        mygroup = rocketchat.groups()[group]
        while True:
            print(count)
            mygroup.send('*testmessage* ' + str(count))
            count += 1
            if count == 3000:
                mygroup.send('room successfully trashed')
                if verbose == True:
                    print('room trashed successfully!')
                break                    

[/code]

once saved, use the following examples:

first install example:

[code]
./rc-client.py –install –rcuser rocketchatuser –rcpass rocketchatpass –rchost http://chat.reiners.io
[/code]

delete messages from channel:
[code]
./rc-client.py –delete –iknow –channel general
[/code]

delete messages from room:
[code]
./rc-client.py –delete –iknow –group mygroup
[/code]

send a message to a group:
[code]
./rc-client.py –send –group mygroup –text “Hello there”
[/code]

send a message to a channel:
[code]
./rc-client.py –send –channel general –text “Hello there”
[/code]

send a message to a user:
[code]
/.rc-client.py –send –user username –text “Hello there”
[/code]

fill a channel with test messages:
[code]
./rc-client.py –trash –channel general
[/code]

file a group with test messages:
[code]
./rc-client.py –trash –group mygroup
[/code]

HAPROXY, The easy load balancer

Posted Leave a comment

Load balancing the easy way, with haproxy. I use this all the time with docker. This example will balance 53, across 6 DNS backends. To tweak for your use, you can change the stats port, username and password, and backend servers to your setup.

port 1936 will show the cluster health page. port 53 will round-robin balance across the 6 hosts, and will also pull them out if not healthy, adding them back once health checks pass!

global  
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 4096
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon

defaults  
        log     global
        mode    http
        option  httplog
        option  dontlognull
        option redispatch
        retries 3
        maxconn 2000
        contimeout      5000
        clitimeout      50000
        srvtimeout      50000

listen stats :1936  
        balance
        mode http
        stats enable
        stats auth username:password


listen myservice :53  
        mode tcp
        option tcplog
        balance roundrobin

        server dns0 192.168.10.1:53 check
        server dns1 192.168.10.2:53 check
        server dns2 192.168.10.3:53 check
        server dns3 192.168.10.4:53 check
        server dns4 192.168.20.5:53 check
        server dns5 192.168.20.6:53 check

Dockerized Power Meter Reading

Posted Leave a comment

I’ve dockerized my Centos 7 meter reading application, if you want to check it out, it’s over on my github account here.

The basics:

I’ve created a docker-compose.yml file to build a set of 4 machines, with persistent storage. All you need us a software defined radio. I purchased mine on Amazon for less than $40.

Here I’ll be describing a little how-to of how the containers work, and how to use them.

metermaid.yml

version: '3.1'

services:

  weatherdb:
    image: mariadb
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: weatherdb
    ports:
            - 3306:3306
    volumes:
            - weather-mysql:/var/lib/mysql
    networks:
            - weather

  grafana:
    image: grafana/grafana
    restart: always
    ports:
            - 3000:3000
    volumes:
            - grafana-storage:/var/lib/grafana
    networks:
            - weather
    depends_on:
            - weatherdb

  metermaid:
    build: ./metermaid/
    ports:
            - 1234:1234
    volumes:
            #- metermaid-storage:/app
            - /dev/bus/usb:/dev/bus/usb

    privileged: True
    networks:
            - weather
    depends_on:
            - weatherdb

  weatherscript:
    build: ./weather/
    restart: always
    networks:
            - weather
    depends_on:
            - weatherdb

volumes:  
  weather-mysql:
  grafana-storage:
  metermaid-storage:

The yaml is pretty straightforward actually, which surprised me about docker. As you can see I’m starting 4 machines.

  • weatherdb – a straight MariaDB host, here because this app doesn’t need to be secure, and to simplify setup, I’m passing the password using an environmental variable. You can access this machine from a mysql client by connecting to mysql -h$dockerhost -uroot -ppassword on normal port 3306. The volume is a persistent type, you can tell because it’s a name before the column, instead of a path.

  • grafana – this machine is also just an official grafana docker container from docker hub. The only difference I have made is persistent storage and a dependency on the MariaDB host. You can access this machine using http://$dockerhost:3000

  • metermaid – metermaid is fairly specific docker container, I’ll post the docker code below. It is a centos 7 official instance, that I install prerequisites on. This instance will start rtl-tcp and handle all connections to the radio, and saving of all meter data to mysql. The entrypoint is the metermaid python application.

Please note the metermaid machine needs to run with privileged, so it can see usb, which is mounted (/dev/bus/usb:/dev/bus/usb). the metermaid machine will basically have root access, but being a specific purposed machine, meant for home users, this should be safe. It uses a network of its own and does no actual web calls. It’s still safe to port forward 3000 to grafana, its a completely different machine with no privileges.

From centos:latest  
RUN yum -y update  
RUN yum -y install wget vim tar epel-release git nc tee tree && yum -y install rtl-sdr python34 python34-mysql python34-pip  
RUN wget https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz  
RUN tar -xvf go1.10.1.linux-amd64.tar.gz && mv go /usr/local/  
RUN mkdir /projects/  
RUN mkdir -p /app/bin && cd /app/bin  
ENV GOROOT=/usr/local/go  
ENV GOPATH=/projects  
ENV PATH=$GOPATH/bin:$GOROOT/bin:$PATH:/app/bin/  
COPY code /app/bin/  
RUN python3 -m pip install pymysql  
RUN /usr/local/go/bin/go get github.com/bemasher/rtlamr && /usr/local/go/bin/go get github.com/bemasher/rtlamr-collect  
RUN python3 -m pip install mysql-connector-python simplejson mysql-connector requests  
ENTRYPOINT python3 /app/bin/metermaid.py
  • weatherscript – This machine is similar to the other custom instance, I’m just changing the entry point to a for loop to hit the weather API every 5 minutes, and store the data. I’ll leave my API in there for now, but if you enjoy this script, please feel free to edit the script, and sign up for your own free account. I believe I used openweather API.
From centos:latest  
RUN yum -y update  
RUN yum -y install wget vim tar epel-release git nc && yum -y install rtl-sdr python34 python34-mysql python34-pip  
RUN wget https://dl.google.com/go/go1.10.1.linux-amd64.tar.gz  
RUN tar -xf go1.10.1.linux-amd64.tar.gz && mv go /usr/local/  
RUN mkdir /projects/  
RUN mkdir -p /app/bin && cd /app/bin  
ENV GOROOT=/usr/local/go  
ENV GOPATH=/projects  
ENV PATH=$GOPATH/bin:$GOROOT/bin:$PATH:/app/bin/MeterMaid  
COPY code /app/bin/  
RUN python3 -m pip install pymysql mysql-connector-python simplejson mysql-connector requests  
ENTRYPOINT bash /app/bin/run.sh  
So how do I use this?

Decide where you want the machine to run, I have a home server so it was a decent choice since the machine is always running. The nice thing about docker is Host OS should not matter. These instructions are for a GNU Linux host. Specifically Centos 7.

Install docker.

sudo yum install docker docker-compose  

Once installed grab my git repo here.

$ git clone https://github.com/jreiners/metermaid-docker.git
$ cd metermaid-docker
$ docker-compose -f metermaid.yml build --no-cache

This part takes a few minutes, and as you can see, it will download, and completely set up a working environment that will collect all readings it can see and saves them to persistent SQL. You can hit control-C if you can log into sql, and hit grafana on 3306(mysql) and 3000(grafana)

once it’s running there are a couple finishing steps you need to do. Which is create the database, and two tables to hold your meter data and weather info.

[justin@localhost ~]$ mysql -h192.168.1.163 -uroot -pweatherdb
Welcome to the MariaDB monitor.  Commands end with ; or g.  
Your MariaDB connection id is 389  
Server version: 10.3.7-MariaDB-1:10.3.7+maria~jessie mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

MariaDB [(none)]> create database metermaid;  
Query OK, 1 row affected (0.00 sec)

This stack will autorestart if anything stops working, and will even start on reboot if you make sure docker is in startup (systemctl enable docker)

You can find your meter serial number on a sticker on the meter itself. Electricity, gas, and water meters all should have a white sticker. Please keep this in mind: sometimes you cannot find one or two meters. My water does not work at my place, the meter has a label, but it just never communicates in a way the software-defined radio can see it. This could be a different encoding, or frequency higher or lower than my radio can see.

Please let me know what you think!

If you run into issues, please make sure nothing else is using your SDR and it’s plugged into the machine and working. on the host

SQL commands:

metermaid needs the following two tables, and one database created on first boot. these will persist.

metermaid needs the following database, and two tables created. You can use the mysql client, or use the query editor in grafana.

database:

create database metermaid  

utilities:

CREATE TABLE `utilities` (  
  `mPrimaryKey` int(6) unsigned NOT NULL AUTO_INCREMENT,
  `mId` varchar(50) DEFAULT NULL,
  `mType` int(2) DEFAULT NULL,
  `mTime` int(11) DEFAULT NULL,
  `mTotalConsumption` int(11) DEFAULT NULL,
  `mConsumed` float DEFAULT NULL,
  PRIMARY KEY (`mPrimaryKey`)
) ENGINE=InnoDB AUTO_INCREMENT=142010 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED

weather:

CREATE TABLE `weatherdb` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `epoch` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
  `mintemp` float DEFAULT NULL,
  `maxtemp` float DEFAULT NULL,
  `currenttemp` float DEFAULT NULL,
  `windspeed` float DEFAULT NULL,
  `winddir` varchar(3) DEFAULT NULL,
  `text1` varchar(30) DEFAULT NULL,
  `text2` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=250 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED
Grafana example queries:

Electric Meter:

SELECT  
  mId as metric,
  mTime as time_sec,
  mConsumed as value
FROM UtilityMon.UtilityMeter  
WHERE  
  mId=5744xxxx
and  
  $__unixEpochFilter(mTime)
;

Gas Meter:

SELECT  
  mId as metric,
  mTime as time_sec,
  mConsumed as value
FROM UtilityMon.UtilityMeter  
WHERE  
  mId=6592xxxx
and  
  $__unixEpochFilter(mTime)
;

Neighborhood Electric Meters:

SELECT  
  mType,
  mId as metric,
  mTime as time_sec,
  mConsumed as value
FROM UtilityMon.UtilityMeter  
WHERE  
  mType=7
and  
  $__unixEpochFilter(mTime)
;

Neighborhood Gas Meters:

SELECT  
  mType,
  mId as metric,
  mTime as time_sec,
  mConsumed as value
FROM UtilityMon.UtilityMeter  
WHERE  
  mType=12
and  
  $__unixEpochFilter(mTime)
;

My old metermaid machine was lost in an outage, so I need to redo my weather query. I’ll update this page when I get it graphing with temp again in grafana.

Installing docker and couchbase on CentOS 7

Posted Leave a comment

Installing docker on CentOS 7

sudo yum install docker  
sudo systemctl enable docker  
sudo systemctl start docker  

Install the docker image:

sudo docker run -d --name db -p 8091-8094:8091-8094 -p 11210:11210 couchbase  

and open the configuration wizard
http://localhost:8091

to enable your docker container on boot, find your container id:

[root@cam ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS              PORTS                                        NAMES  
525449b441da        kerberos/kerberos   "/bin/bash /runny.sh"   9 minutes ago       Up 9 minutes        0.0.0.0:86->80/tcp, 0.0.0.0:8895->8889/tcp   3rdelevator  

When you find the container ID, startup policies can be changed with docker update

[root@cam ~]# docker update --restart=always 525449b441da
525449b441da