Welcome to Cowlug


Site Navigation

This site is my personal blog and project repository.

If you are looking for the old Cowichan Valley Linux Users Group, check the side navigation. This site contains links to various projects that I either created or contribute to.

You will also find my Github page and Youtube channel here.



Latest News


Home Assistant component development

This is my attempt to document the development of a component and binary_sensor for the Home Assistant project. This page will fill in over the coming days.


Ok lets start with the basics. I have a hardware device called a W800RF32A, it's a radio that receives data from X10 devices such as the KR19A, MS16A and the RSS16. Please see this page for a picture of the devices. They are keypads and motion sensors.

The W800RF32A receives data and transmits it to the computer via an RS232 serial link, There are also USB versions which should work fine. The W800RF32 can also be built using a 310MHz receiver module and an Arduino. We will cover that in another article.

So, why are we doing this, well, while the Home Assistant documentation is pretty good, it has a few weak areas, some examples tend to be a bit lacking in information and it is spread out over many pages. I tend to like a concise example that is documented all in one place.

Having said that, it would be a good idea for the new developer to read the following sections on the Home Assistant 101 page.

Right, lets start with a high level block diagram of what we are trying to accomplish, then we can dive into the code.
Here is the block diagram from the HA site. We are going to develop the Platform and the Component.



For our purposes and simplicity, I think we can safely reduce this down to the following:

The next step is to boil the code down into blocks we need to have. Here is where the Home Assistant documentation does a credible job but fails in some of the detail. For areas that are covered well by the HA documentation I will link to, rather than duplicating.

Our component, we need to do the following:

    1. Import required python libraries
    2. Import HA constants, helpers and entities
    3. Add our requirements
    4. Set a DOMAIN
    5. Set some global constants and other variable we will require
    6. Setup the LOGGER
    7. Grab configuration from the yaml file
    8. Run setup
    9. Add required logic

For our platform, we need to do the following:

    1. Import required python libraries
    2. Import HA W800rf32 component, binary_senor component, constants, helpers and entities
    3. Add our dependencies
    4. Set some global constants and other variable we will require
    5. Setup the LOGGER
    6. Grab configuration from the yaml file
    7. Run setup_platform
    8. Add required logic and binary sensor object

There will of course be some things that are part of both pieces of code and obviously we won't break those down in both cases. This is a long article and for those that want have the raw code and follow along or modify for there own purposes here are the links:

Note: I have renamed these files adding the component and platform portion. These files would normally live in the following folders with the assumption that Home Assistant is installed in:

/home/ha

Please note: This is a working piece of code but has not been accepted upstream yet.

The component file:
/home/ha/home-assistant/homeassistant/components/w800rf32.py
W800rf32 component code

The platform file:
/home/ha/home-assistant/homeassistant/components/binary_sensor/w800rf32.py
W800rf32 platform code

W800rf32 component code

"""
Support for w800rf32 components.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/w800rf32/

This is the configuration for our component, it is from the configuration.yaml file. "w800rf32" is the DOMAIN as set below and device is the serial port our w800 hardware is connected to.

# Example configuration.yaml entry
w800rf32:
  device: PATH_TO_DEVICE

Imports

The next section shows the imports we need, remeber this is a fairly simple component, more complex components will have more imports. The logging and voluptuous imports are fairly normal python libraries.

"""
import logging
import voluptuous as vol


These are pretty obvious ~/homeassistant/const.py holds the constants for the Home Assistant project. Almost all of the constants are strings so you could just use the string, however, if the HA project changes a constant it is global, so best to use them.

    1. ATTR_ENTITY_ID = 'entity_id' <- the platform ID of an entity, ie: a light, switch, sensor etc
    2. ATTR_NAME = 'name' <- the name given the entity
    3. ATTR_STATE = 'state' <- the state (on/off) of the entity
    4. CONF_DEVICE = 'device'<- the component device from config, in this case the serial port
    5. CONF_DEVICES = 'devices'<- the platform devices from config, indiviual binary_sensors
    6. EVENT_HOMEASSISTANT_START = 'homeassistant_start'<- event that fires upon HA startup
    7. EVENT_HOMEASSISTANT_STOP = 'homeassistant_stop'<- event that fires upon HA shutdown

from homeassistant.const import (
     ATTR_ENTITY_ID, ATTR_NAME, ATTR_STATE, CONF_DEVICE, CONF_DEVICES,
     EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)

Import the config_validation, explained below.

import homeassistant.helpers.config_validation as cv

Import HA Entity class which holds methods and properties such as entity name, state, device_class, icon etc. This class can be inherited and methods and properties can be overridden in your component, you will often see this in components to add functionality specific to that component.

See this for an example at the bottom of the file.


from homeassistant.helpers.entity import Entity

Requirements

HA covers the REQUIREMENTS section well, here is the link.
In a nutshell REQUIREMENTS is a project on PYPI that gets pulled into HA (pip install) and is responsible for encoding and decoding data from the hardware.


REQUIREMENTS = ['pyW800rf32']

Domain

DOMAIN is how your component will be known under HA. Since my hardware is a W800rf32A, I opted to call my DOMAIN 'w800rf32'.
The DOMAIN is a value stored in a dictionary called config and holds such items as config[DOMAIN][ATTR_DEVICE], which in this case, is the serial port the w800rf32 is connected to.

The code in ~/homeassistant/config.py reads the configuration.yaml file and stores the information in config[DOMAIN].


DOMAIN = 'w800rf32'

Constants

These are constants that we use, that are not defined in the ~/homeassistant/const.py file. They are specific to this component.


CONF_FIRE_EVENT = 'fire_event'
CONF_DEBUG = 'debug'
CONF_OFF_DELAY = 'off_delay'
EVENT_BUTTON_PRESSED = 'button_pressed'
RECEIVED_EVT_SUBSCRIBERS = []
W800_DEVICES = {}

Logger

This is the python logger and just returns the name of the module for logging. HA covers the LOGGING section well, except it seems it's not well linked to. here is the link.


_LOGGER = logging.getLogger(__name__)

Configuration

The voluptuous library is used to validate the schema of the configuration data, set in the configuration.yaml file (or possibly an included file).
In this component we have two variables allowed in the configuration.yaml file:
    1. "device": which is CONF_DEVICE
    2. "debug": which is CONF_DEBUG

Just to refresh your memory, the configuration.yaml file looks like so:
w800rf32:
  device: /dev/ttyUSB0
  debug: False
device is a required parameter, in other words it must be present. It's value, in this case '/dev/ttyUSB0',is also checked to be a string value (cv.string).
debug is optional and has a default value if it isn't present in the configuration.yaml file and is checked, if present, for a boolean value.

The extra=vol.ALLOW_EXTRA is there to allow additional keys in the data that are not listed in the schema, from throwing an exception.


CONFIG_SCHEMA = vol.Schema({
    DOMAIN: vol.Schema({
        vol.Required(CONF_DEVICE): cv.string,
        vol.Optional(CONF_DEBUG, default=False): cv.boolean,
    }),
}, extra=vol.ALLOW_EXTRA)

setup()

Called from: homeassistant.setup
Returns: True

Setup is where we actually setup our component for HA.


First we should come up with a check list of things to do:
    1. Define a setup function and pass in the hass object and the config dictionary
    2. Setup an event handler to deal with in coming data
    3. Import the W800rf32 module
    4. Get the device from config, call connect and return an w800_object
    5. Setup two event handlers to deal with HA start and stop events
    6. Hand our w800_object over to hass
    7. Return if all is well

Setup is pretty simple, just define a function passing in the hass object and the config dictionary.
The hass object is described here. It is the HA instamce that has access to all the parts of the running HA system.

def setup(hass, config):
    """Set up the w800rf32 component."""

Define an event handler to handle data coming from the hardware. This is fairly simple, it just logs the event and then runs a handler for the specific entity. This could be simplified, however, it's a good way to write it, if you want expanded functionality in a more complex component.
handle_receive gets added to the HA event loop when HA starts running, see code below.

    # Declare the Handle event
    def handle_receive(event):
        """Handle received messages from w800rf32 gateway."""
        # Log event
        if not event.device:
            return
        _LOGGER.debug("Receive W800rf32 event in handle_receive")

This code is a list of event functions (the subscriber), which is added in the platform code.
When data is received from hardware, it triggers the handle_receive function which logs it and then runs the subscriber(event), in this case binary_sensor_update() from the platform code.

        # Callback to HA registered components.
        for subscriber in RECEIVED_EVT_SUBSCRIBERS:
            subscriber(event)

Load the W800rf32 module (REQUIREMENTS) which was installed from the PYPI repository. The HA documentation requests that modules are loaded in functions and not globaly at the top.

    # Try to load the W800rf32 module.
    import W800rf32 as w800

Right, next thing we need to do is grab the serial port device form the configuration.yaml file which was parsed into the config dictionary.
If we break this down it would look like so: device = config['w800rf32']['device']

Now call the Connect function in the PYPI module code that opens the serial port and setups the event handlers, returning an object. Remeber HA doesn't want us to do any lowlevel handling of the hardware in HA code, it must be a third party PYPI module.

    # device --> /dev/ttyUSB0
    device = config[DOMAIN][CONF_DEVICE]
    w800_object = w800.Connect(device, None)

Define two small functions and add them to the HA event loop, for events that get triggered on startup and shutdown of HA.
_start_w800rf32() is where the handle_receive function listed above gets added to the HA event loop.

    def _start_w800rf32(event):
        w800_object.event_callback = handle_receive
    hass.bus.listen_once(EVENT_HOMEASSISTANT_START, _start_w800rf32)

_shutdown_w800rf32() should be fairly obvious.

    def _shutdown_w800rf32(event):
        """Close connection with w800rf32."""
        w800_object.close_connection()
    hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, _shutdown_w800rf32)

The last task in setup is to add our object to the global hass.data dictionary and then return True

    hass.data['w800object'] = w800_object
    return True

apply_received_command()

Called from: (platform) w800rf32.binary_sensor_update()
Returns: None

apply_received_command applies a command received from an event, from the hardware through the platform and PYPI code.

def apply_received_command(event):
    """Apply command from w800rf32."""
Get the device and command from the event, in this case the device will an X10 code, example: A1 or G4 and either 'On' or 'Off' for the command.
    device_id = event.device.lower()
    command = event.command
    # Check if entity exists or previously added automatically
    if device_id not in W800_DEVICES:
        return

    _LOGGER.debug(
        "Device_id: %s, Command: %s",
        device_id,
        command
    )

Check if command is valid and then call update_state which is part of the w800rf32BinarySensor class within our platform code. This in turn will schedule a state update in HA.
    if command == 'On' or command == 'Off':
        # Update the w800rf32 device state
        is_on = command == 'On'
        W800_DEVICES[device_id].update_state(is_on)
If we need to fire and event, which we would configure in configuration.yaml then run this code and log it.
    # Fire event
    if W800_DEVICES[device_id].should_fire_event:
        W800_DEVICES[device_id].hass.bus.fire(
            EVENT_BUTTON_PRESSED, {
                ATTR_ENTITY_ID:
                    W800_DEVICES[device_id].entity_id,
                ATTR_STATE: command.lower()
            }
        )
        _LOGGER.debug(
            "w800rf32 fired event: (event_type: %s, %s: %s, %s: %s)",
            EVENT_BUTTON_PRESSED,
            ATTR_ENTITY_ID,
            W800_DEVICES[device_id].entity_id,
            ATTR_STATE,
            command.lower()
        )

W800rf32 platform code

"""
Support for w800rf32 binary sensors.

For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/binary_sensor.w800rf32/

# Example configuration.yaml entry

binary_sensor:
  - platform: w800rf32
    devices:
      c1:
        name: motion_hall
        off_delay: 5
        device_class: Motion
      c2:
        name: motion_kitchen
        device_class: Motion

"""
import logging

import voluptuous as vol

from homeassistant.components import w800rf32
from homeassistant.components.binary_sensor import (
    DEVICE_CLASSES_SCHEMA, PLATFORM_SCHEMA, BinarySensorDevice)
from homeassistant.components.w800rf32 import (
    ATTR_NAME, CONF_DEVICES, CONF_FIRE_EVENT, CONF_OFF_DELAY)
from homeassistant.const import (
    CONF_COMMAND_OFF, CONF_COMMAND_ON, CONF_DEVICE_CLASS, CONF_NAME)
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers import event as evt
from homeassistant.util import dt as dt_util


_LOGGER = logging.getLogger(__name__)

DEPENDENCIES = ['w800rf32']

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Optional(CONF_DEVICES, default={}): {
        cv.string: vol.Schema({
            vol.Optional(CONF_NAME): cv.string,
            vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
            vol.Optional(CONF_FIRE_EVENT, default=False): cv.boolean,
            vol.Optional(CONF_OFF_DELAY):
            vol.Any(cv.time_period, cv.positive_timedelta),
            vol.Optional(CONF_COMMAND_ON): cv.byte,
            vol.Optional(CONF_COMMAND_OFF): cv.byte
        })
    },
}, extra=vol.ALLOW_EXTRA)


def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Binary Sensor platform to w800rf32."""
    import W800rf32 as w800rf32mod
    sensors = []

    # device_id --> "c1 or a3" X10 device. entity (type dictionary) --> name, device_class etc
    for device_id, entity in config[CONF_DEVICES].items():

        if device_id in w800rf32.W800_DEVICES:
            continue

        _LOGGER.debug("Add %s w800rf32.binary_sensor (class %s)",
                      entity[ATTR_NAME], entity.get(CONF_DEVICE_CLASS))

        event = None
        device = w800rf32BinarySensor(
            event, entity.get(CONF_NAME), entity.get(CONF_DEVICE_CLASS),
            entity[CONF_FIRE_EVENT], entity.get(CONF_OFF_DELAY))

        device.hass = hass
        sensors.append(device)
        w800rf32.W800_DEVICES[device_id] = device

    add_entities(sensors)

    def binary_sensor_update(event):
        """Call for control updates from the w800rf32 gateway."""
        sensor = None

        if not isinstance(event, w800rf32mod.W800rf32Event):
            return

        # make sure it's lowercase
        device_id = event.device.lower()

        # get the name, ex: motion_hall
        if device_id in w800rf32.W800_DEVICES:
            sensor = w800rf32.W800_DEVICES[device_id]

        if sensor is None:
            return
        elif not isinstance(sensor, w800rf32BinarySensor):
            return
        else:
            _LOGGER.debug(
                "Binary sensor update (Device ID: %s Class: %s)",
                event.device,
                event.device.__class__.__name__)

        w800rf32.apply_received_command(event)

        if (sensor.is_on and sensor.off_delay is not None and
                sensor.delay_listener is None):

            def off_delay_listener(now):
                """Switch device off after a delay."""
                sensor.delay_listener = None
                sensor.update_state(False)

            sensor.delay_listener = evt.track_point_in_time(
                hass, off_delay_listener, dt_util.utcnow() + sensor.off_delay)

    # Subscribe to main w800rf32 events
    if binary_sensor_update not in w800rf32.RECEIVED_EVT_SUBSCRIBERS:
        w800rf32.RECEIVED_EVT_SUBSCRIBERS.append(binary_sensor_update)


class w800rf32BinarySensor(BinarySensorDevice):
    """A representation of a w800rf32 binary sensor."""

    def __init__(self, event, name, device_class=None,
                 should_fire=False, off_delay=None):
        """Initialize the w800rf32 sensor."""
        self.event = event
        self._name = name
        self._should_fire_event = should_fire
        self._device_class = device_class
        self._off_delay = off_delay
        self._state = False
        self.delay_listener = None


    @property
    def name(self):
        """Return the device name."""
        return self._name

    @property
    def should_poll(self):
        """No polling needed."""
        return False

    @property
    def should_fire_event(self):
        """Return is the device must fire event."""
        return self._should_fire_event

    @property
    def device_class(self):
        """Return the sensor class."""
        return self._device_class

    @property
    def off_delay(self):
        """Return the off_delay attribute value."""
        return self._off_delay

    @property
    def is_on(self):
        """Return true if the sensor state is True."""
        return self._state

    def update_state(self, state):
        """Update the state of the device."""
        self._state = state
        self.schedule_update_ha_state()

Python driver for the W800rf32 family of X10 RF receivers

I recently put a driver up on PYPI for the W800rf32 family of X10 RF receivers from WGL & Associates.
I use this with the following devices:

KR19A
MS16A
RSS18

Here is the github page: W800RF32

This is available to install via PIP:

pip3 install pyW800rf32

All of the logic for the decoding I wrote for the Pytomation project.
Here is an example of using the code, note: very little error checking here.
My reason for doing a PYPI project was to write and include a driver for Home Assistant.

QRP Labs Enclosure for the LimeSDR.

I recently got a LimeSDR board and also bought a QRP Labs case for it. The QRP Labs case brings all the RF connectors out to the front and rear panels and also includes heatsinks for the chips and a case fan.
Assembly instructions are here.

.
Parts list:

    1. 12pcs SMA to U.FL pigtails
    2. aluminium shell bottom (4 holes)
    3. aluminium shell top (fan cutout, 2 holes)
    4. 4 rubber pads
    5. 4 plastic screws
    6. 8 plastic nuts
    7. fan 30x30 5v with mesh
    8. pinheader
    9. heatpad (1pcs, cut later into more pcs)
    10. 6pcs heatsinks (1x + 2x + 3x)
    11. PCB panel (front, rear)
    12. 8 panel screws
    13. 4 bicolor LEDs
    14. 2 LED holders

Software: There are four software packages that I use with the LimeSDR as well as the LimeSuite from Myraid RF.

Users especially Hams should consider the HF mod https://wiki.myriadrf.org/LimeSDR_HF_Performance

Pytomation running on Pi3 with TFT display and power circuit.

I recently got a TFT display and a serial port board with a small bit of breadboard space hooked up to my Raspberry Pi3, for running Pytomation. See the side menu for more about automation with Pytomation. I wanted something I could power down, removing power from the Pi board, then start up again with the push of a button. The entire assembly is built with the following components (see the article from January about configuring the TFT display):

.

This is the Pi serial expansion board including breadboard area. It is available from https://www.abelectronics.co.uk.


.

This is the schematic of the power circuit. It works as follows:

Once the Pi has booted pressing the bottom button on the TFT display, which is connected to GPIO 17, will initiate a shutdown of the operating system, The very last action taken during the shutdown sequence is to enable (logic high, +3.3v) GPIO pin 26. GPIO 26 turns on the "set" coil of the relay which in turn will remove power from the Pi board. The 470uF capacitor provides just enough additional power to the Pi to properly latch the relay before removing power. Pressing the pushbutton will pulse the "reset" coil and power will be restored to the Pi, which then boots.

Here is a quick video of the board operating.

Parts list:
    1. Raspberry Pi3 with USB power supply and SD card, running Raspbian 9.
    2. Adafruit 2.8" Capacitive display from BC Robotics
    3. SerialPiPlus an RS232 board with breadboard space.
    4. 3.3 volt dual coil latching relay model EE2-3TNU.
    5. 3.3volt three terminal regulator.
    6. IN4148 diode.
    7. Green LED.
    8. 470 ohm, 1/4 or 1/8 watt resister
    9. Normally open pushbutton switch.
    10. 470uF, 25volt electrolytic capacitor.
    11. USB male connector/cable end.
    12. Various standoffs and hardware.

Once the board is complete with the power on/off circuit you must make some changes to your Raspbian installation. There are two things that must be done. Add support for the power down button on the TFT display and add support for GPIO pin 26 to change to a high state (3.3v) one it is safe to remove power from the Pi3.

To get the TFT display working see my article from January 2018, PiTFT

TFT display button support:
This tells the Pi to watch GPIO pin 27 which is one of the buttons on the TFT display, when pressed it will shutdown the Pi.
Login and edit the /boot/config.txt file to add the following at the bottom of the file.
dtoverlay=gpio-shutdown,gpio_pin=27

This is from the /boot/overlays/README file.

Name:   gpio-shutdown
Info:   Initiates a shutdown when GPIO pin changes. The given GPIO pin
        is configured as an input key that generates KEY_POWER events.
        This event is handled by systemd-logind by initiating a
        shutdown. Systemd versions older than 225 need an udev rule
        enable listening to the input device:

                ACTION!="REMOVE", SUBSYSTEM=="input", KERNEL=="event*", \
                        SUBSYSTEMS=="platform", DRIVERS=="gpio-keys", \
                        ATTRS{keys}=="116", TAG+="power-switch"

        This overlay only handles shutdown. After shutdown, the system
        can be powered up again by driving GPIO3 low. The default
        configuration uses GPIO3 with a pullup, so if you connect a
        button between GPIO3 and GND (pin 5 and 6 on the 40-pin header),
        you get a shutdown and power-up button.
Load:   dtoverlay=gpio-shutdown,=
Params: gpio_pin                GPIO pin to trigger on (default 3)

        active_low              When this is 1 (active low), a falling
                                edge generates a key down event and a
                                rising edge generates a key up event.
                                When this is 0 (active high), this is
                                reversed. The default is 1 (active low).

        gpio_pull               Desired pull-up/down state (off, down, up)
                                Default is "up".

                                Note that the default pin (GPIO3) has an
                                external pullup.


GPIO pin 26 support:
Login and edit the /boot/config.txt file to add the following at the bottom of the file.
dtoverlay=gpio-poweroff,gpiopin=26

This is from the /boot/overlays/README file.
Name:   gpio-poweroff
Info:   Drives a GPIO high or low on poweroff (including halt). Enabling this
        overlay will prevent the ability to boot by driving GPIO3 low.
Load:   dtoverlay=gpio-poweroff,=
Params: gpiopin                 GPIO for signalling (default 26)

        active_low              Set if the power control device requires a
                                high->low transition to trigger a power-down.
                                Note that this will require the support of a
                                custom dt-blob.bin to prevent a power-down
                                during the boot process, and that a reboot
                                will also cause the pin to go low.

Now assemble all the pieces. Stack the serialpi board on the Pi first , then the TFT display hat on top of the serial board, then power on your Pi. You should be able to safely shutdown the Pi by pushing the bottom button on the TFT display. To turn the Pi back on, press the pushbutton wired into the power circuit.

Here is a picture of the completed project:
.


PiTFT small displays for Raspberry Pi

This explains what I had to do to get the Adafruit 2.8" Capacitive display working under Debian Stretch on a Raspberry Pi 3.

.

At this point in time, January 2018, the tutorial on the Adafruit page only deals with getting the displays working under Debian Jessie. Stretch was released on June 17th, 2017 and it's a bit sad that Adafruit has not updated their tutorial.

Here are the steps:
    1. Install Debian Stretch on your Pi3. I used the 2017-08-17 image from downloads.raspberrypi.org.
    2. Make sure everything is up to date with: sudo apt-get update and then sudo apt-get upgrade, then reboot.
    3. Download the adafruit-piftf-helper2.sh script from here, I have a local version here but it may be old now, please check.
    4. Make the script executable -> chmod +x adafruit-pitft-helper2.sh
    5. Now run the script with the sudo command -> sudo ./adafruit-pitft-helper2.sh
    6. and answer the questions


Microscope

Just picked up one of these microscopes for surface mount work.

Features:

  • High quality optical glass elements
  • High definition erect stereo images over a wide field view
  • 2 levels of total magnifications: 10X and 20X
  • Extremely long working distance allows enough operation space
  • 45┬░inclined binocular head
  • Low heat LED light - harmless for touching
  • Additional flexible lamp holder provided for different lighting angles
  • Ocular tube has diopter adjustment
  • Adjustable inter-pupillary distance to fit anyone's eyes
  • Sturdy small metal boom stand
  • Product GS and CE approved
  • Manufacturer in business 30+ years

Specifications:
  • Model: G22C
  • Head: 45┬░Inclined binocular.
  • Eyepieces: wide field WF10X/20 and WF20X/10
  • Objective: 1x
  • Total magnification: 10x & 20x
  • Ocular tube has diopter adjustment ┬▒5dp
  • Interpupillary distance: 2-3/16" ~ 2-15/16"(55~75mm)
  • Working distance: 9 " (230mm)
  • Maximum field of view: 3/4" (20mm)
  • Focus adjustment stroke: 1-3/4" (43mm)
  • LED illumination
  • Power supply: 110V/60Hz (US and Canada)
  • Dimension: 18" x 5-1/8" x 15" (46cm x 13cm x 38cm)
  • Net weight: 14 lb 12oz ( 6.7kg)
  • Shipping weight: 17 lb (8kg)



Hue Commander

I have released a Linux console, python utility, called "huecmdr.py". You can use it to test various aspects of the Philips HUE lighting system. It runs great in any X terminal as well.

It has the following features:

  • Authenticate your computer with the bridge
  • Ask the bridge to search for newly purchased bulbs
  • List all the bulbs known to the bridge
  • Select a bulb for testing
    • Test various values of
    • RGB colours
    • Colour temperature
    • Hue and Saturation
    • Brightness

This utility is a great way of selecting a value to use in your Pytomation Instance file. You can find the Source on the Pytomation github site.



H19term

H19term aims to provide close to 100 percent software emulation of the Heathkit H19, also known as Zenith Z19, hardware video terminal.

It currently has the following features:

  • Software bell - User configurable sound
  • Heath mode
  • Ansi mode
  • Supports 25th line.
  • Support all graphics characters.
  • Custom font files for the Linux console, includes Raspberry Pi
  • Serial Port logging.
  • Help files available for ascii characters, CP/M quick help and user manual.
  • Easily configurable in .h19termrc file
  • Colour changing mode for Amber and Green or other colours.
  • Help files directly inside h19term.

Requirements

H19term is written in Python version 2.7. It won't run in Python 3.x without some modifications.

You will also require the Pyserial package. The Pyserial home page is here if you want more information about it. You can install it with your standard package manager

Download

Download the h19term tarball and follow the instructions in the README file.

The github page is https://github.com/horga83/h19term

Installation

See the h19-readme.txt file or go to the github page and scroll down.

As noted before Python should already be installed in most Linux distributions.

Videos

Inital Release. Release V1.2



DD for CP/M

DD.COM - CP/M Disk dump

DD.COM is a floppy imaging program for CP/M. It is modelled after the UNIX utility dd. It allows one to make a floppy disk image from an H8D file or to dump the floppy disk to an H8D image.

How it works.

Disk dump for CP/M - Version 1.2 - 2012/01/13...

dd currently only works for reading and writing H8D CP/M disk images to and from an H17, 100k, hard sector diskette drive.

Usage:
dd - Prints out the help.
dd map - Prints a map of your disk drives - must have floppy inserted.
dd if=<file|drive|port> of=<drive|file|port> - copies images.

Example:
dd if=e: of=cpmboot.h8d - Makes image from E: drive called cpmboot.h8d
dd if=mydisk.h8d of=d: - Images D: drive from file mydisk.h8d
dd if=ttys1: of=d: - Images D: drive from serial port using h8clxfer or H89LDR9.

Downloads

You can download the BDS C source code and the compiled, ready to run versions of DD.COM here.
DD.COM version 1.2 --- DD-1-2.C Source

Older versions

DD.COM version 1.1 --- DD-1-1.C Source

Versions

1.0 - 2012/01/01
- Initial version

1.1 - 2012/01/06
- Dig drive letter out of filename so it uses the the correct drive when doing a bisoh(SELDSK).
- Add version and date to help.
- Add drive type to map display.

1.2 - 2012/01/13
- Added serial port support which can be used with Dwight's H89LDR program or h8trans/h8clxfer.

Other Information

Error checking is a little weak yet but I'm working on it, for example, it fails if a diskette isn't inserted in the drive. The program is written in BDS C so it is easy to extend. I will be adding the ability to work with H89LDR so one can use the serial port from a PC as well.

I have only tested this with the following configuration so if it doesn't work for you send me a bug report and I'll fix it. H8 with IDE hard drives A-D and H17 floppy drive E:

Just remember you MUST have a formatted floppy inserted in the drive before you copy.