Hawkeye conversion from X10 to Thorian

(circa 2018)

 

 

 

About

This was one of my bigger challenges — converting a Hawkeye MS14A PIR motion sensor, originally running a PIC12C508 with X10 RF protocol, into a fully Thorian-compatible sensor. The goal was to retain the existing PIR hardware and repurpose the casing, while rewriting the microcontroller code entirely to support the Thorian wireless protocol.
 

Background & Research

The Hawkeye is a remarkably efficient motion sensor. Initial testing showed:

~50 μA idle at 3 V

~450 μA when active

Up to 2 mA during RF transmission bursts

It uses a PIC12C508 8-pin microcontroller, which handles PIR input, daylight sensing, and X10 RF communication. Interestingly, several pins on the PIC serve dual functions, including both I/O and communication. This made tracing and decoding the firmware slightly more involved.

My Firmware:

Written in Assembly (main.asm) with X10 routines in transRF10.inc

Delay and timing logic in delays02.inc

Final compiled file: PIC12F1501.hex

 

Circuit info

The unit is powered by 2× AAA batteries (3 V total)

Motion is detected using a PIR element amplified by a TLC27 op-amp

Ambient light sensing is done via an LDR

RF transmission is handled by a discrete RF oscillator + transistor stage

The PCB shows creative use of shared signal lines

Photos and reverse-engineering annotations:

 

Signal mapping

 

 

Conversion process

Desoldered the PIC12C508 and replaced it with a socket for flexibility.

Wired up the PIC12F1501 for development and programming using a PICkit 3.

Carefully traced and documented all signal paths from the original schematic.

Used original hardware:

PIR amplifier (TLC27 op-amp)

RF transmitter circuit

Green and red LEDs

AAA battery power

Wrote new code for the PIC12F1501 that:

Reads PIR motion and ambient light

Responds with encoded Thorian RF packets

Sleeps between detections for ultra-low power

 

 

 

 

Firmware and Integration


The new firmware is 100% custom-written in Assembly for the 12F1501. It maintains the same ultra-low power profile by sleeping most of the time and only waking on motion.

Key features:

Idle power: ~50 μA

Active sense: ~450 μA

TX burst: ~2 mA (short duration only)

Protocol: Fully compatible with Thorian

NOTE: The original main.asm and X10 code (transRF10.inc) are preserved for future reference and disassembly comparison.

 

 
View Thorian Firmware (main.asm)
; 12F1501 Hawkeye MS14A Replacement Firmware - Thorian Protocol
; Author: Ian Thorington (2018)
; Version: v05
; Description: Custom firmware to replace X10 with Thorian RF protocol.
; Runs ultra-low power PIR sensor with interrupt and RF transmission.

; === CONFIGURATION ===
#include p12f1501.inc
LIST P=PIC12F1501,ST=OFF,R=DEC
errorlevel -302

__CONFIG _CONFIG1 , _FOSC_INTOSC & _WDTE_SWDTEN & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF
__CONFIG _CONFIG2 , _WRT_OFF & _STVREN_OFF & _BORV_HI & _LPBOR_OFF & _LVP_OFF

; === VARIABLES ===
enablePIR       EQU 0x04
TX              EQU 0x05
temp            EQU 0x21
twoloops        EQU 0x22
bytes           EQU 0x23
temperatureH    EQU 0x24
temperatureL    EQU 0x25
RFaddress       EQU 0x26
RFdata          EQU 0x27
RFdataComp      EQU 0x28
count           EQU 0x29
counter         EQU 0x2A
devicetype      EQU 0x2B
deviceaddress   EQU 0x2C
data1           EQU 0x2D
delayCounter    EQU 0x2E
delayValue      EQU 0x2F
ADDRH           EQU 0x70
ADDRL           EQU 0x71

; === RESET VECTOR ===
RST code 0x0
        goto Start
        NOP
        NOP
        NOP
        GOTO PIR_TRIPPED

; === MAIN CODE SEGMENT ===
PGM code

Start:
    ; === Oscillator Setup ===
    BANKSEL OSCCON
    MOVLW b'01101010'        ; 4 MHz internal clock
    MOVWF OSCCON
Stable:
    BTFSS OSCSTAT, HFIOFR
    GOTO Stable              ; Wait until oscillator stable

    ; === Watchdog Setup ===
    BANKSEL WDTCON
    MOVLW B'00011100'        ; 16 sec (simulator), enable WDT
    MOVWF WDTCON

    ; === I/O Setup ===
    BANKSEL TRISA
    MOVLW B'00001011'        ; Configure RA pins: RA5-TX, RA4-enablePIR, etc.
    MOVWF TRISA

    BANKSEL ANSELA
    CLRF ANSELA              ; All digital
    BANKSEL 0

    BSF LATA, 2              ; Red LED off (active low)
    BCF LATA, enablePIR      ; Enable PIR (active low)
    BCF LATA, TX             ; TX pin low

    ; === Interrupt Setup ===
    BANKSEL IOCAP
    BSF IOCAP, IOCAP0        ; Interrupt on rising edge RA0 (PIR)
    BANKSEL INTCON
    BSF INTCON, IOCIE        ; Enable IOC interrupt
    BCF INTCON, IOCIF        ; Clear interrupt flag
    BSF INTCON, 7            ; Enable global interrupt
    BANKSEL 0

    ; === Initial RF Packet ===
    MOVLW D'4'				; THIS IS THE DEVICES ADDRESS AND SHOULD BE SET TO ANYTHING BETWEEN 1-254
    MOVWF deviceaddress		 
    MOVLW D'1'
    MOVWF temperatureL
    MOVLW D'0'
    MOVWF temperatureH
    CALL RFtx                ; Send boot/test packet

PIRLOOP:
    NOP
    NOP
tired:
    NOP
    NOP
    MOVLW 200
    CALL MSdelay
    SLEEP                    ; Go to sleep, wake on interrupt
    NOP
    NOP
    NOP
    GOTO PIRLOOP

; === Interrupt Handler ===
PIR_TRIPPED:
    BANKSEL INTCON
    BCF INTCON, IOCIE        ; Disable interrupt
    BANKSEL 0

    CALL RFtx                ; Send RF message first (before LED)
    BCF LATA, 2              ; RED LED ON

checkPIR:
    BSF LATA, enablePIR      ; Disable PIR (active low logic)
    CALL secondDelay
    BSF LATA, 2              ; RED LED OFF
    BCF LATA, enablePIR      ; Enable PIR again

    BTFSC PORTA, 0
    GOTO checkPIR            ; Wait for PIR to settle

    ; === Extra RF Notification ===
    BSF LATA, enablePIR
    MOVLW 200
    CALL MSdelay
    MOVLW 200
    CALL MSdelay
    MOVLW 255
    CALL MSdelay
    CALL RFtx

    ; === Sleep Until Next Trigger ===
    BANKSEL WDTCON
    BSF WDTCON, SWDTEN       ; Enable watchdog (8 sec)
    CLRWDT
    SLEEP
    NOP
    NOP
    NOP
    BCF WDTCON, SWDTEN       ; Disable watchdog

    ; === Re-enable Interrupts ===
    BANKSEL INTCON
    BSF INTCON, IOCIE
    BCF INTCON, IOCIF
    BANKSEL IOCAF
    BCF IOCAF, 0
    BANKSEL 0

    BCF LATA, enablePIR      ; Re-enable PIR
    RETFIE

; === Includes ===
include delays02.inc
include transRF10.inc
END
View RF Transmit Routine (transRF10.inc)
; Thorian RF Transmit Routine
; Sends a structured RF packet:
; - Preamble for AGC sync
; - Address byte
; - Data bytes (e.g. temperatureL, temperatureH)
; - Stop bit
; Uses LATA.5 as the RF output pin (change if needed)

RFtx:                           ; Start of transmission
    ; === Preamble ===
    ; AGC burst: 9ms on, 4.5ms off (to wake up/sync receiver)
    bsf     LATA, 5             ; Set RF pin HIGH
    movlw   D'18'               ; 9ms
    call    MSdelay
    bcf     LATA, 5             ; Set RF pin LOW
    movlw   D'9'                ; 4.5ms
    call    MSdelay

    ; === Address Byte ===
    movf    deviceaddress, w    ; Load device address
    movwf   data1
    call    doRFbyte

    ; === Data 1: temperatureL ===
    movf    temperatureL, w
    movwf   data1
    call    doRFbyte

    ; === Data 2: temperatureH ===
    movf    temperatureH, w
    movwf   data1
    call    doRFbyte

    ; === Data 3: Unused (send blank) ===
    clrw
    movwf   data1
    call    doRFbyte

    ; === Stop Bit ===
    bsf     LATA, 5
    movlw   D'33'               ; ~336us pulse
    call    uSdelay
    bcf     LATA, 5

    ; Optional: Wait before retransmitting
    movlw   D'81'               ; 40ms delay
    call    MSdelay
    bcf     LATA, 5
    return

; ================================
; Transmit 1 byte + its inverse
; Each bit: ~330us HIGH, then delay based on bit value

doRFbyte:
    movlw   0x02                ; 2 loops: original + inverted byte
    movwf   bytes

byteloop:
    movlw   0x08                ; 8 bits
    movwf   count

rfloop:
    bsf     LATA, 5             ; Start bit (HIGH)
    movlw   D'33'               ; ~330us
    call    uSdelay

    bcf     LATA, 5             ; End bit (LOW)
    movlw   D'23'               ; Default off time (~230us for 0)
    btfsc   data1, 7            ; If bit7 is 1, skip next
    movlw   D'80'               ; Longer off for 1 bit (~800us)
    call    uSdelay

    rlf     data1               ; Rotate left (get next bit into bit7)
    decfsz  count, f
    goto    rfloop

    comf    data1, f            ; Invert byte for second pass
    decfsz  bytes, f
    goto    byteloop
    return
 

 

Final Result


The converted Hawkeye now acts as a drop-in, battery-powered motion sensor for my Thorian ecosystem.

No physical changes to the casing or lens

All components reused

Completely silent and efficient

Much lower power than even the ESP-based sensors

Now emits Thorian packets upon motion detection, with light-level gating

 

Files

The link to the assembly and hex files are here

IMPORTANT - The device address is set to 4. To change this, you will need to change it in the ASM file and recomplile the code.

Other Thorian devices include an ICSP header which allows easy reprogramming. This unit does not, so changes require desoldering the re-flashing the chip.

 

Unfortunately no Labcenter Proteus simulation this time. The 12F1501 chip is too new and isn't supported in my version of Proteus.

It took a long time to write the code for this.

 

 

 

 

 

← Back to Projects