Saturday, 9 June 2018

Humax FVP-4000T remote control app


Introduction

I've owned a Humax FVP-4000T Freeview unit for a while and overall it performs well and has plenty of useful features (https://uk.humaxdigital.com/product/fvp-4000t/).
It is connected to my home network and therefore the Internet. One small disappointment is the quality of the Infra-Red remote control handset, with some of the buttons occasionally being unresponsive or inconsistent in operation. I also own an old HUDL tablet and I installed the Humax remote control application for Android. This app has most of the controls necessary to operate the FVP-4000T, but the screen display isn't optimised for the HUDL, so this can be slightly frustrating to use. As the control from the HUDL to the FVP-4000T is via my wireless and wired network, the control is easier and more reliable than the infra red unit, so it's frequently in use.

I began to wonder whether an app might be available for Microsoft Windows so I could control the FVP-4000T from my laptop (running Win 8.1), but my initial searches proved fruitless.

One resource I found proved useful in that some control codes had been identified that the Humax Android app uses to control Humax boxes. This can be found at:


This got me thinking about whether I could produce my own app using the Python programming language. I've only been using Python for a couple of years on and off, so do not consider myself at all proficient. There may be some poor aspects of the programming in my script that I developed, or there may be a better way of doing some of the elements, but I got an application working how I expected it to work. I've learned a lot on the way, and I extend my thanks to anyone who has posted Python code snippets or asked questions or given answers on-line.


There were a number of things I needed to investigate as part of this project.

1. Find out which network address, protocols and port the Humax FVP-4000T 'listens' for control codes.
2. What the Humax app that runs on the HUDL sends and the format of the information used.
3. Create a 'window' based Python application - to run as a standalone executable on Windows.

For this write up I have assumed the reader understands many basic concepts relating to network protocols and the Python programming language. There are many good resources on the Internet which should help with understanding these topics.


Network address, protocols and ports
Initially I set a fixed IP address on the Humax FVP-4000T box so that any network investigations would be easier; the last thing I wanted was to 'chase' around finding the FVP-4000T network address every time I worked on this project.


I used Wireshark (https://www.wireshark.org/) installed on my laptop to capture the network traffic sent from my Humax app on my Hudl tablet to determine the protocols, ports and control codes. I used a network splitter cable so I could monitor the traffic from my tablet to the FVP-4000T via my home router.

When the Android Humax app starts it sends out an SSDP (Simple Service Discover Protocol) message.[https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol] discovery 

The Wireshark capture:










In response, the Humax sends:





Here the Humax IP address is identified and also the MAC address. This was to prove useful during the development of my app as I wanted to be able to discover the Humax IP address automatically and confirm that the IP address is assigned to a Humax unit.


Humax Control Codes

Running the Android app I experimented using the 'Mute' control - mainly because when using the app control I could hear when the Humax audio was present or not and didn't need to monitor the TV screen. Also, just using one function should help to identify the code(s) in the network data.
The information I confirmed was that the Android app uses UDP (User Datagram Protocol) [https://en.wikipedia.org/wiki/User_Datagram_Protocol] to send the control message and the Humax destination port is 22558.

The Wireshark capture:


The next information comprises:












In remote control mode, this data comprises the control data which is always:
686d78726100000072637500000000003030

Note that the byte codes 72, 63, 75 equate to 'rcu' - a 'pointer' to Remote Control Unit

The code for 'Mute' in this example above is ascii 72,  byte codes 37, 32.
The complete control message becomes:
686d787261000000726375000000000030303732

I checked some more of the codes from (https://hummy.tv/forum/threads/ip-remote-commands.7783/) to confirm that the control and data format was consistent.

Further investigation revealed a different control data format when performing searches on the Humax.

When using the search function, the control data becomes:
686d7872610000006b65790000000000332c302c

Note that the control data used in 'remote control mode' to select the search mode on the Humax  replaces the 3030 with 332c and adds 302c. Also, the byte codes 6b, 65, 79 equate to 'key' -  a pointer to 'Key text search'.

Actual search text appears after this control data. For example, the text letter 'a' appears as:
686d7872610000006b65790000000000332c302c61 (61 byte code = 'a')

All the information to control the Humax FVP-4000T was now known. I had to investigate how I could use Python3 to develop a set of control functions within a windows interface.


Python script
The key elements needed:
1. Send an SSDP message to find the Humax box details (IP & MAC addresses)
2. Confirm a valid Humax MAC address
3. Set up the host PC to send UDP data
4. Construct remote control and search control messages
5. Create a Graphical User Interface (windows) with selectable functions
6. Define functions - when user selects, the script sends the command
7. Enable user to enter search text and send to the Humax


SSDP Message
I found a Python script which I modified that enabled me to send SSDP messages. When experimenting with my Humax unit, the message returned included :

uuid:1E96FF1A-6771-2F44-A0C5-2c088c9931f9


After some investigation I determined that the elements '2c088c' is an identifier for the Humax MAC vendor ID.  On line I found a range of vendor ID Humax MAC addresses that I included in my application code as part of confirming the IP address associated with its MAC address. It is intended this app 'should' work with different Humax boxes if they have one of the vendor ID MAC addresses I've included in the Python script. See 'Using the application' at the end of this blog if this application doesn't work with your Humax box.

The script extract below creates the SSDP message, sets the SSDP IP, configures the IP socket, sends the message and captures the response(s). It checks for a valid MAC address, extracts the IP address and sets the variable UDP_IP as the 'target' IP address and the port number to 22558 for future messages to be sent to the Humax box.
  
import socket
msg = \
    'M-SEARCH * HTTP/1.1\r\n' \
    'HOST:239.255.255.250:1900\r\n' \
    'ST:upnp:rootdevice\r\n' \
    'MX:2\r\n' \
    'MAN:"ssdp:discover"\r\n' \
    '\r\n'

msg1 = msg.encode()

ssdp_udp = '239.255.255.250'

# Set up UDP socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
s.settimeout(2)
s.sendto(msg1,(ssdp_udp, 1900))

#humax mac ids (valid mac addresses as of May 2018)
macs = (
    'e820e2', 'dcd321', 'cc4eec', 'a0722c', '942cb3', '940937', '90f305',
    '6cb56b', '4cd08a', '403dec', '3438b7', '2c088c', '2832c5', '08eb74',
    '044f17', '000378'
    )

# receive ssdp responses
try:
    while True:
        data, addr = s.recvfrom(65507) #addr format ('xxx.xxx.xxx.xxx', 1900)
        inputtext = str(data)
        for var in range(len(macs)): # check for valid humax mac address
            query = (inputtext.find(macs[var]))
            if (query != -1):
                ipads = str(addr)
                comma = (ipads.find(","))
                extract = (ipads[2:comma-1]) # get the IP address
               
except socket.timeout:
    pass

#IP is 'extracted' from the ssdp search response
UDP_IP = extract
UDP_PORT = 22558

Remote Control & Search Control Messages
Previously I stated that the Remote Control Message format had a static element. This is used here below, one called 'Control' for the Remote Control,  the other 'Controlkey' for accessing the Search function on the Humax box.

#Static HUMAX message element
Control = bytes.fromhex('686d78726100000072637500000000003030')

Controlkey = bytes.fromhex('686d7872610000006b65790000000000332c302c')

To construct a complete Remote Control Message, the function code is added to the Control Message element. For example the Mute function code is '3732'. The defined Python function looks like:

def Mute():
    SendCmd(bytes.fromhex('3732'))

When the Mute function is selected, it then calls the SendCmd function and passes the hex code to be added to the Control message element. The complete message is then sent to the Humax box.

def SendCmd(code): # Construct full HUMAX control message & send
    Message = Control + code
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.sendto(Message, (UDP_IP, UDP_PORT))

I created a series of functions to cover the range of remote control functions available on the Humax. These functions, together with the remote control codes are viewable in the Python script.


Programme Search
To construct a Remote Control Message to do a programme search on the Humax unit, first a Control Message is constructed and sent to the Humax box.  The function to do this is below which opens up the search box on the Humax.  (I include the Windows GUI code, which creates a search text entry box for the user to enter text, a graphical button to submit the entered search text to a Python function to extract the entered text, construct the text string and send to the Humax unit).

# search function creates text entry box & submit button
def Search():
    SendCmd(bytes.fromhex('3437'))
    global textstr #global to be available to Dialog function
    textstr=StringVar()
    textentry=Entry(myGUI, width=12, textvariable=textstr).grid(row=1,column=6)
    button1=Button(myGUI, text='Submit', width=6, command=Dialog).grid(row=2,column=6)

# get entered text & format to send to Humax box
def Dialog(): # send ascii letters to Humax search box
    text = str(textstr.get()) # get text search entry box
    c = len(text) # variable for string length
    pointer = 0 # starting point in string
    cs = "" # hex string construction variable
    while  pointer < c:
        # construct hex characters string without leading 0x, from decimal values of text
        cs=cs+(hex(ord(text[pointer])).replace("0x",""))
        pointer = pointer+1 # move along the string
        SendKey(bytes.fromhex(cs)) # use constructed string as the 'code' to add to the 'control' msg
   
def SendKey(code): # Construct full HUMAX search control + text & send
    Message = Controlkey + code
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    sock.sendto(Message, (UDP_IP, UDP_PORT))


Windows Graphical User Interface (GUI)
The interface I created is fairly simple and clean, and laid out to suit how I use the controls. The Python code can be modified to create a different layout.




When the Search 'button' is selected, the text entry box and submit button appears.




To create the windows interface:

from tkinter import *
# create Window GUI
myGUI = Tk()
myGUI.geometry('550x215')
myGUI.title('HUMAX FVP-4000T Remote Control IP: ' + extract) # include IP address in header
myGUI.resizable(False, False)

All the main Python code follows this code including all the functions and GUI graphical elements.
The final line should be:

myGUI.mainloop()

Within the Python script I include all the codes and functions that worked and those which didn't.



Using the application
If you have Python3 with the Integrated Development Environment (IDE) installed on your machine you can download my script, open it in the IDE and run from there (use F5).

Alternatively download the GUI.exe application below with all the associated files in the 'GUI' folder. When run, a command window will open as well as the GUI window. Research indicates it's possible to run the GUI while suppressing the command window, but I haven't got this to function correctly.

This executable and associated files was made using the application called PyInstaller. PyInstaller converts a .py script to a Windows executable, standalone .exe file.

This can be found at: https://www.pyinstaller.org/

If my PyInstaller files do not work on your machine I suggest downloading PyInstaller on your own machine, and use it to convert my GUI.py script on your own machine.

When running the application (ensure your Humax box is powered up) there will be a short delay of about 3 to 5 seconds as your Humax unit is identified, then the GUI appears. The GUI will not appear if your Humax unit is not identified if your Humax unit MAC address is not listed in my Python script.

One work around to overcome this:
Modify my Python script to remove all the code associated with the SSDP function. In the code element (UDP_IP=extract), replace 'extract' with the IP address of your Humax unit. It's recommended that the Humax unit is assigned a fixed IP address.

Alternatively, modify the Python script to include the MAC address element of your Humax unit. This address should be on the unit.

The GUI controls should be straightforward to use.

When using the Search function, the Humax search screen appears. After entering the text in the text entry box on the application and selecting Submit, the text should appear in the Humax search box. Selecting Search again on the application then 'applies' this as the search text on the Humax box and the search results should appear.

The Power button only works to turn the Humax unit power off.

Navigation around the Humax functions is by the Left, Right, Up and Down buttons. CH- and CH+ work to change programmes, but also scrolls screens when viewing the TV guide or Recordings listings.

I hope you find this application helpful. If you don't like any elements of the programme you are free to modify it to your own taste.

If you find it useful please leave some comments on my blog.

Downloads:

GUI.py (Python3 script) (12KB)

Windows Executable (.exe) and related files in folder 'GUI' (20MB)


Thursday, 16 November 2017

Small LED string power supply

Background:
Last year I purchased a small LED lighting strip as a Christmas decoration. It was powered by two 1.5v batteries and whilst the lighting strip gave an effective display I found that the batteries didn't last too long. This year I investigated an alternative 3 volt power source and I also wanted to make use of some spare components I had.

I had a 240 volts (AC) mains power block for providing 5v DC to charge Sony Ericsson mobile phones and using this as the primary power source I investigated a suitable 3 volt regulator. The LP2950-30 provided the solution. I put together the simple circuit below. LED D1 provides an indication that the 5v supply is available. Capacitors C1 and C2 provide stability of operation for the voltage regulator as recommended in the LP2950-30 datasheet.

Specifications:
Input voltage supply 5v @ 450mA Sony Ericsson power block.

Output voltage 3v @ 100mA (max), to supply 50mA for LED string.


5v to 3v voltage converter circuit

Construction :
The circuit components were mounted on a very small piece of veroboard, placed within a small plastic box - Hammond 1551GBK.

To maintain separation of input and output connections, a 2.5mm DC power socket was used for the 5v input supply with a 2.1mm DC power socket used for the 3v output supply. The LED was mounted next to the input socket to act as a reminder that the neighbouring socket is for 5v input.

Operation:
The LED strip connects to the output socket using a 2.1mm DC power plug. The 5v power block connects to the input socket using a 2.5mm DC power plug. A regulated and stable 3v was measured at the output, with current draw of 51mA. Initially running for an hour with the plastic box lid fitted, the regulator was cool to the touch - working well below its maximum current capability. No more batteries will be required! Images of the completed unit are below:


Circuit board mounted within small box

Lights are on, no more batteries!!

Components:
LP2950-30 (3v Regulator)
2.2uF 50v Electrolytic capacitor (2)
D1 - Red LED as main power supply indicator
LED panel mounting socket
R1 - 220 ohms 0.25w
Supply input socket 2.5mm DC socket
Supply input plug 2.5mm DC plug to connect 5v power block
Supply output socket 2.1mm DC socket
Supply output plug 2.1mm DC plug to connect to LED string cable
Plastic project box Hammond 1551GBK 50x35x20mm
Veroboard for circuit mounting

Thursday, 2 November 2017

Passive Infra-Red Controlled LED Strip Lighting

Introduction

In my house there is an inglenook fireplace which houses a wood burner.
Ordinarily the fireplace is quite a dark place being recessed and I wanted to provide some lighting to take the darkness away and to light up the natural stone.

After searching for lighting and considering the powering options I decided to install an LED lighting string. These strings come in various sizes and can be cut to length. Powered usually by 12 volt power supply I wanted to hide as much cable and components from view.

Looking at various switching options I decided to design a switching unit based on a Passive Infra-Red (PIR) detector and power transistor to switch the 12 volt LED string on and off.

The main challenges to address are that the PIR detector alone can only switch low power circuits and the PIR output is limited to a short 'on' time once activated. What was required is that the PIR detector should operate with a single hand gesture with circuitry to switch the LED string on, and with another hand gesture, the PIR switches the LED string off.  The PIR module will be mounted out of sight underneath the inside of the fireplace recess, so a single hand wave will be sufficient for the module to detect movement. One wave will switch the LED string on, with another wave switching the LED string off.


The circuit below achieves what I required.

Passive Infra-Red LED string switching controller
Circuit description

The PIR module detection sensitivity is set so that it is triggered when movement is as close as possible to avoid spurious activity. The 'on-time' is set to its shortest time, as all that is required is a single pulse output from detected movement.

The PIR module output is fed to a CMOS dual D-Type Flip-Flop. Only one Flip-Flop of the CD4013 is needed in this example. The Flip-Flop is configured so that when the PIR output changes from Low to High, the output of the CD4013 (Q) goes High. When the PIR output returns to Low condition, the Q output of the Flip-Flop remains High. Only when another transition from Low to High on the PIR output takes place will the Flip-Flop change its output from High to Low. In effect the CD4013 Flip-Flop is performing a divide by 2 operation, but in this case its output can be used effectively as a latch.

The output from the CD4013 is fed to Q1, MOSFET  RFP12N10L. The MOSFET is switching 12volts to the LED string, and with the length of string I needed, the total current draw was approximately 0.5 Amp. The MOSFET is working well within the operating specifications and does not experience any rise in temperature, which is important as I chose to mount the circuitry in a sealed aluminium box.

I included the LED (D1) as a switching indicator. Should the LED string fail to operate and D1 is on, this will indicate that the LED string has failed.

The PIR module and CD4013 require a 5v supply. The power regulator 78L05 provides this and is capable of supplying up to 100mA.

Pins 8, 9, 10 & 11 of the CD4013 are taken to 0v. [not shown on the circuit diagram above]

Operating currents
In operation, this circuit draws a relatively small amount of power; indeed when inactive, current draw is almost zero.

The following total current measurements were taken:
PIR inactive: 51uA
PIR active: 0.375mA
CD4013 inactive: 0
CD4013 active: 41uA
LED strip off: 51uA
LED strip on (3 metre length): 400mA
LED1 on draws 1.6mA

References / data sheets

Saturday, 1 April 2017

Data Encoder/Decoder HT12E/HT12D

Data Encoder / Decoder
HT12E / HT12D

Introduction

I recently came across an old article I had kept from the Radio Society of Great Britain magazine (Radcomm) May 1998 by G6AWT, entitled 'A Versatile Remote Control System', in which a pair of encoding and decoding processors named the HT12E and HT12D had been used to provide remote control functions for radio equipment.

I wondered whether these processors were still available - they are! I began to think about how I could use this technology with the current range of micro-controllers such as the Arduino and the Raspberry Pi, together with other potential uses. I also thought it would be a great opportunity to fully investigate the operation of the two processors to help me better understand how I might use these in the future.


HT12E & HT12D description and operation
These devices are made by HOLTEK and have common applications in car and garage door controllers, smoke and fire alarms, burglar and car alarms, security systems etc .

The encoder (HT12E) is capable of encoding information comprising 12 bits in total; 8 address bits and 4 data bits. Each address/data bit can be set to either High or Low logic states. The output from the encoder can be used in various ways; for example to feed a Radio Frequency or infrared transmitter , or it could be directly connected to a decoding processor.  Eight address bits allows for one encoder / transmitter combination to use 1 of 256 addresses, each one capable of sending 1 of 16 different data values. This address/data combination allows the possibilities of using one encoder to control many remote receivers with HT12D decoders. The outputs from the HT12D decoder can be used to switch connected logic circuitry or other attached devices via suitable interfaces.

HT12E Encoder circuit

The basic circuit arrangements for the encoder:


The address to use is selected by connecting one or more pins A0 - A7 to 0 volts. If left 'open', that is, not connected to 0 volts, the address will be all '1's or logic HIGH on each pin. The same process is applied to the data bits. If left open, these data bits are at logic 1 or HIGH. OSC1 is the on board oscillator input pin, OSC2 is the oscillator output pin. These two pins are connected together via resistor R, in this case its value is 1Mohm. When the XMIT button is pressed to take pin 14 to 0 volts, the address and data bit stream appears at pin 17 DOUT. The data stream comprises one synchronising bit followed by 8 address bits and 4 data bits. The oscilloscope trace below shows one complete cycle comprising the synchronising bit, 8 address bits and 4 data bits. All address bits and data bits are at logic '1'. In this example the HT12E is powered at 3.3v.


If pin 14 (Transmit Enable) is permanently taken to ground (0v), the encoder continuously transmits the data stream. If a short enable pulse is applied to pin 14, in this case 5mS, one complete transmit cycle is produced comprising 4 cycles, see trace below:


Selecting data pin AD8 and taking this to ground (0v) produces the following data stream:



Selecting address pin A0 and taking this to ground (0v) while AD8 is also at 0v, produces the following data stream:



HT12D Decoder circuit

The basic circuit arrangements for the decoder:



The address to use is selected by connecting one or more pins A0 - A7 to 0 volts. If left 'open', that is, not connected to 0 volts, the address will be all '1's or logic HIGH on each pin. For correct operation between the HT12E and HT12D, the address values must be the same. OSC1 is the on board oscillator input pin, OSC2 is the oscillator output pin. These two pins are connected together via resistor R, in this case its value is 33kohm. The data sheets for both HT12D and HT12E provide details of suitable resistor values. When a data stream from the HT12E encoder is applied to pin 14, DIN, the decoder compares the input data three times with the locally selected address. If no errors are present the input data codes are decoded and latch transferred to the data output pins D8 - D11. The data levels remain 'latched' until a different data set is received. These output pins can be connected to other logic circuitry or external devices via suitable interfaces, as they are unable to provide high current drive. The VT (Valid Transmission pin) pin 17 goes high to indicate a valid transmission and in the circuit above, the LED is switched on. In this example the HT12D is powered at 3.3v.


Using simple 433Mhz Transmitter and Receiver for communications between HT12E & HT12D

Having proved correct operation between the HT12E and HT12D by directly connecting the DOUT to the DIN, I investigated using the basic 433Mhz transmitter and receiver combination in the image below. Transmitter on the left, receiver on the right.


I had little success with these units without any external antennas, so I investigated some options. I took the design for a simple wound coil antenna from an 'Instructables' article. http://www.instructables.com/id/433-MHz-Coil-loaded-antenna/

With these antennas attached during some experimentation I managed to get a reliable communications link of approximately 5 metres. I didn't spend any time trying to optimise the antennas, but early results were encouraging.

Connect the DOUT from the HT12E to the data input on the transmitter module, and apply +3.3v power and ground to the transmitter. The output from the 433Mhz receiver module is connected via an inverter. During inactive periods, the receiver output can be at +3.3v so when a data stream is received, the first positive going synchronising pulse does not get correctly presented to the HT12D and therefore the first cycle would be discounted leaving only 3 cycles (the minimum) for checking. Also, I noted that the output from the 433Mhz receiver is an inverse of the data stream. Using a BC337 NPN transistor as an emitter follower provides a simple inverting function drawing very small amounts of current. Basic circuits below:



Examining the output directly from the HT12E DOUT pin and the BC337 Emitter/R4 junction (HT12D input) confirms the data stream has been correctly received over the 433Mhz communications link. 




In the following trace, address bit A0 is set LOW. Note you can see a very small time lag between the top trace HT12E Data out and the BC337 inverter output (HT12D Data input)  due to the time taken to pass through the 433Mhz TX/RX link.


Using the Raspberry Pi to control

I further experimented with the Raspberry Pi to set the HT12E data pins (AD8 - AD11) using the GPIO pins. Additionally, I used another GPIO pin to act as the trigger for the HT12E. I haven't drawn any circuits for this as the interfacing is straight forward as both the Raspberry Pi and the HT12E operate at 3.3v.
The 4 Raspberry Pi GPIO pins needed to set the HT12E data bits can be directly connected to the HT12E. The GPIO pin acting as the trigger function needs connecting via an inverter circuit. This is to ensure that when the Raspberry Pi GPIO pin is taken 'HIGH' a corresponding 'LOW' is present at the HT12E trigger pin.

I have included a simple Python3 script below, which prompts the user to enter a number between 0 and 15, and using Binary Coded Decimal, sets the AD8 - AD11 pins to convey the user entered number correctly. I have experimented further with this, connecting LEDs to the HT12D decoder data pins to ensure the transmitted and received data is presented correctly. I also used the HT12D data output pins connected to a TTL IC 7447 (BCD to 7-Segment display driver) and a 7-segment display. I have referenced this before in an earlier blog and the direct link is: (http://www.electronics-tutorials.ws/counter/bcd-counter-circuit.html).

Using the Python script below (GPIO_HT12E.py), when a number is entered (0-9) the 7-Segment display shows the number. It could be said that this is a very convoluted way to use this technology but it was really useful to experiment and prove that it was possible.

I can see many uses for the HT12E/D combination, especially when used with either the Raspberry Pi or Arduino. The transmission of the data stream can be over an RF link or direct connection using 2-core cable. With the possibilities of using multiple decoders (HT12D) all 'listening' on their individually configured addresses it is possible for the Raspberry Pi or Arduino to control both the address values and control the use of the data pins. It would be possible to control literally hundreds of external devices this way. To break out the HT12D 4 data output pins further, it is possible to connect these to a 4 to 16 decoder such as the MC14514 / 74HC4514 to get 16 individual output pins. Just one HT12E/D combination could control up to 16 different devices, ideal for something like a model railway layout controlling signals, points, lights etc.


Python3 script:

# Python v3.4.2 console based script
# Set Raspberry Pi GPIO ports Low depending on user input
# User enters number between 0 and 15, GPIO ports 22, 23, 24 & 25
# are set as BCD representations of the decimal input.
# GPIO ports are weighted 0, 2, 4, 8 [GPIO 22, 23, 24, 25]
# Number 99 entered quits the script
# GPIO ports connect to AD8-11 ports on HT12E encoder chip
# user input is BCD coded & used to set AD8-11 ports
# GPIO port 17 is used to send trigger pulse to activate the HT12E for 1 complete cycle


import RPi.GPIO as GPIO # import GPIO module
import time

GPIO.setwarnings(False) # disable warning messages
GPIO.setmode(GPIO.BCM)  # use chip GPIO pin numbers

GPIO.setup(17, GPIO.OUT)
GPIO.output(17, GPIO.LOW)
GPIO.setup(22, GPIO.OUT)
GPIO.output(22, GPIO.HIGH)
GPIO.setup(23, GPIO.OUT)
GPIO.output(23, GPIO.HIGH)
GPIO.setup(24, GPIO.OUT)
GPIO.output(24, GPIO.HIGH)
GPIO.setup(25, GPIO.OUT)
GPIO.output(25, GPIO.HIGH)

def One():
    GPIO.output(22, GPIO.LOW)

def Two():
    GPIO.output(23, GPIO.LOW)

def Four():
    GPIO.output(24, GPIO.LOW)

def Eight():
    GPIO.output(25, GPIO.LOW)

def ClearAll():
    GPIO.output(22, GPIO.HIGH)
    GPIO.output(23, GPIO.HIGH)
    GPIO.output(24, GPIO.HIGH)
    GPIO.output(25, GPIO.HIGH)

def Trigger():
    GPIO.output(17, GPIO.HIGH)
    time.sleep(0.005)
    GPIO.output(17, GPIO.LOW)

try:
    while True:
        print ("Setting GPIO ports Decimal to BCD")
        print ("Enter number between 0 and 15 [99 quits]")
        print ("Warning! supplied parameters are not validated")
        decimal = input(">_ ") # get number as a string
        print
        dec_number = int(decimal) # convert string to integer
        if dec_number != 99:
            ClearAll() # set A8-11 ports to '0000'
            Trigger() # send trigger pulse
            time.sleep(0.1)
            if dec_number == 0:
                ClearAll()
                Trigger()
            if dec_number == 1:
                One()
                Trigger()
            if dec_number == 2:
                Two()
                Trigger()
            if dec_number == 3:
                One()
                Two()
                Trigger()
            if dec_number == 4:
                Four()
                Trigger()
            if dec_number == 5:
                One()
                Four()
                Trigger()
            if dec_number == 6:
                Two()
                Four()
                Trigger()
            if dec_number == 7:
                One()
                Two()
                Four()
                Trigger()
            if dec_number == 8:
                Eight()
                Trigger()
            if dec_number == 9:
                One()
                Eight()
                Trigger()
            if dec_number == 10:
                Two()
                Eight()
                Trigger()
            if dec_number == 11:
                One()
                Two()
                Eight()
                Trigger()
            if dec_number == 12:
                Four()
                Eight()
                Trigger()
            if dec_number == 13:
                One()
                Four()
                Eight()
                Trigger()
            if dec_number == 14:
                Two()
                Four()
                Eight()
                Trigger()
            if dec_number == 15:
                One()
                Two()
                Four()
                Eight()
                Trigger()
        else: # user exit
            print ("Exiting..")
            GPIO.cleanup()
            break

except KeyboardInterrupt: # catch the Ctrl-C
    print ("Exit..")
except: # catch other errors
    print ("Error..Exiting")
finally: # clean up on exit
    GPIO.cleanup()


Python3 script GPIO_HT12E.py (Google Drive)