shockcollar

package module
v0.0.0-...-f8e0dde Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 15, 2019 License: BSD-3-Clause Imports: 17 Imported by: 0

README

GoDoc

shockcollar

Raspberry Pi based remote for the Sportdog SD-400 shock collar in Go. It uses rpitx to transmit RF directly to the GPIO. You only need a Raspberry Pi, no other equipment needed.

Web UI Demo

Disclaimers

This software uses rpitx to transmit RF signals directly from the Raspberry Pi's GPIO pins. Before you transmit, know your laws. You are responsible for using this software legally.

This software is really janky. I would strongly discourage you from using this for your production shock collar service. rpitx has also been reported to cause file system corruption in the past, so I would recommend backing up your Raspberry Pi before you attempt to use this software.

This project is not associated with Sportdog.

Getting Started

Plug a wire on GPIO 4 (Pin 7) on the GPIO header. This will serve as the antenna.

Then on your Raspberry Pi:

git clone https://github.com/F5OEO/rpitx.git
cd rpitx
# This is the version of rpitx I've tested with. Newer versions may or may not work.
git checkout 1423af8c6eb201a92d992965e01073717cbc5fdb
./install.sh

go get github.com/biribiribiri/shockcollar
cd $GOPATH/src/github.com/biribiribiri/shockcollar
go get ./...
cd $GOPATH/src/github.com/biribiribiri/shockcollar/remote

# Start the server. Collar commands can be sent via the CLI, gRPC, or via HTTP.
# Needs to be run as root because rpitx needs to be run as root.
# Probably not super secure...
sudo ./remote --rpitx=$PATH_TO_RPITX

After starting the remote, you need to pair your collar:

  1. Turn the collar off.
  2. Press and hold the collar power button until the collar LED turns off (4-5 seconds)
  3. Send the "continuous stimulation" (shock 1 8s) or "beep" (beep 8s) command from the remote until the collar LED blinks 5 times.

A simple web interface will start running on port 8000. You can use this to send commands to the collar.

Reverse Engineering Details

The Sportdog Fieldtrainer 400 (SD-400) is a shock collar with momentary stimulation, continuous stimulation, and tone capabilities. The collar model number is FR-200, and the remote model number is FT-100.

This documentation should apply to any Sportdog training collar compatible with the FT-100 remote (including SD-400, SD-400S and SD-400CAMO).

Communication Protocol

The SD-400 remote uses binary FSK (frequency-shift keying) to send commands to the collar.

The carrier frequency is 27.255 MHz (Citizens Band Channel 23).

This document uses the following symbol definitions: '0': 0 Hz (unmodulated), 4 ms duration '1': 5 kHz modulation, 4 ms duration '2': 5 kHz modulation, 2 ms duration

The 2ms '2' symbol only appears to demarcate the end of a portion of a continuous command. All data symbols are either '0' or '1'.

Commands

There are two classes of commands sent by the remote:

  1. Momentary: Used for the momentary stimulation (nick) function.
  2. Continuous: Used for continuous stimulation and tone function.
Momentary Commands

"Momentary" commands sent by the remote are 43-bits long (172 ms).

Format:
  1 1111 0001 [16-bit remote ID] [8-bit command type] [8-bit command arg] 10
Continuous Commands

"Continuous" commands have a similar structure to the momentary commands, but the transmission sequence repeats for as long as the button is held.

Start:
  1 1111 0001 [16-bit remote ID] [8-bit command type] [8-bit command arg] 102
Repeated N times:
         0001 [16-bit remote ID] [8-bit command type] [8-bit command arg] 102
End:
         0001 [16-bit remote ID] [8-bit command type] [8-bit command arg] 1021111111111

For both momentary and continuous commands, if the remote is in "standby-mode" (no buttons pressed for some time), then the initial sequence of 5 '1's (20ms), becomes 23.5 bits long instead (94ms). However, the collar doesn't seem to require this.

The FT-100 has an 8-position dial, and 3 buttons (up, down, side). In the default Mode 1, these buttons have the following functions:

  • Up: Continuous shock at the specified level for up to 8 seconds.
  • Down: Nick at the specified level.
  • Side: Beep.

At this time, only the Mode 1 commands have been documented. The other modes provide additional functionality, such as exposing 16 levels of continuous stimulation.

Remote IDs

Example remote IDs: 0x6695, 0x999a

The remote is TX-only and the collar is RX-only. A remote has a fixed ID that it broadcasts. A collar will pair to a remote, and will only listen to its paired remote's ID. To pair a collar to a real or emulated remote:

  1. Turn the collar off.
  2. Press and hold the collar power button until the collar LED turns off (4-5 seconds)
  3. Send the "continuous stimulation" or "beep" command from the remote until the collar LED blinks 5 times.

Command and Argument Values

Command Type: Beep (0x59)
  • Arg: 0xa9
Command Type: Nick (0x6a)
  • Level 1: 0xa9
  • Level 2: 0xa6
  • Level 3: 0xa5
  • Level 4: 0x9a
  • Level 5: 0x99
  • Level 6: 0x95
  • Level 7: 0x6a
  • Level 8: 0x55
Command Type: Continuous (0x66)

The arguments are the same as the Nick command.

  • Level 1: 0xa9
  • Level 2: 0xa6
  • Level 3: 0xa5
  • Level 4: 0x9a
  • Level 5: 0x99
  • Level 6: 0x95
  • Level 7: 0x6a
  • Level 8: 0x55

Documentation

Index

Constants

View Source
const (
	// Command start/end sequences. Specified in "binary".
	// '0' represents 4ms, unmodulated
	// '1' represents 4ms, 5kHz modulation
	// '2' represents 2ms, 5kHz modulation
	//
	// Momentary command format:
	//   [CMD_START] [PREAMBLE] [REMOTE ID] [CMD TYPE] [CMD DATA] [MOMENTARY_CMD_END]
	//
	// Continuous command format:
	//   [CMD_START]
	//   Repeated N times: [PREAMBLE] [REMOTE ID] [CMD TYPE] [CMD DATA] [CONTINUOUS_CMD_BREAK]
	//   [CONTINUOUS_CMD_END]
	CMD_START            = "11111"
	PREAMBLE             = "0001"
	MOMENTARY_CMD_END    = "10"
	CONTINUOUS_CMD_BREAK = "102"
	CONTINUOUS_CMD_END   = "1111111111"

	// Command data sequences.
	// These are all specified in hex.
	REMOTE1 = "6695"
	REMOTE2 = "999a"

	CMD_NICK       = "6a"
	CMD_CONTINUOUS = "66"
)

Variables

View Source
var CollarRequest_CommandType_name = map[int32]string{
	0: "UNKNOWN",
	1: "NICK",
	2: "SHOCK",
	3: "BEEP",
}
View Source
var CollarRequest_CommandType_value = map[string]int32{
	"UNKNOWN": 0,
	"NICK":    1,
	"SHOCK":   2,
	"BEEP":    3,
}

Functions

func RegisterCollarServer

func RegisterCollarServer(s *grpc.Server, srv CollarServer)

Types

type CollarClient

type CollarClient interface {
	SendCommand(ctx context.Context, in *CollarRequest, opts ...grpc.CallOption) (*CollarResponse, error)
}

CollarClient is the client API for Collar service.

For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.

func NewCollarClient

func NewCollarClient(cc *grpc.ClientConn) CollarClient

type CollarRequest

type CollarRequest struct {
	Type CollarRequest_CommandType `protobuf:"varint,1,opt,name=type,proto3,enum=shockcollar.CollarRequest_CommandType" json:"type,omitempty"`
	// Command duration in milliseconds. Ignored for the NICK command.
	DurationMs int32 `protobuf:"varint,2,opt,name=duration_ms,json=durationMs,proto3" json:"duration_ms,omitempty"`
	// Intensity for NICK and SHOCK commands. Ranges from 0 to 7 inclusive.
	Intensity            int32    `protobuf:"varint,3,opt,name=intensity,proto3" json:"intensity,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (*CollarRequest) Descriptor

func (*CollarRequest) Descriptor() ([]byte, []int)

func (*CollarRequest) GetDurationMs

func (m *CollarRequest) GetDurationMs() int32

func (*CollarRequest) GetIntensity

func (m *CollarRequest) GetIntensity() int32

func (*CollarRequest) GetType

func (*CollarRequest) ProtoMessage

func (*CollarRequest) ProtoMessage()

func (*CollarRequest) Reset

func (m *CollarRequest) Reset()

func (*CollarRequest) String

func (m *CollarRequest) String() string

func (*CollarRequest) XXX_DiscardUnknown

func (m *CollarRequest) XXX_DiscardUnknown()

func (*CollarRequest) XXX_Marshal

func (m *CollarRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*CollarRequest) XXX_Merge

func (m *CollarRequest) XXX_Merge(src proto.Message)

func (*CollarRequest) XXX_Size

func (m *CollarRequest) XXX_Size() int

func (*CollarRequest) XXX_Unmarshal

func (m *CollarRequest) XXX_Unmarshal(b []byte) error

type CollarRequest_CommandType

type CollarRequest_CommandType int32
const (
	CollarRequest_UNKNOWN CollarRequest_CommandType = 0
	CollarRequest_NICK    CollarRequest_CommandType = 1
	CollarRequest_SHOCK   CollarRequest_CommandType = 2
	CollarRequest_BEEP    CollarRequest_CommandType = 3
)

func (CollarRequest_CommandType) EnumDescriptor

func (CollarRequest_CommandType) EnumDescriptor() ([]byte, []int)

func (CollarRequest_CommandType) String

func (x CollarRequest_CommandType) String() string

type CollarResponse

type CollarResponse struct {
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (*CollarResponse) Descriptor

func (*CollarResponse) Descriptor() ([]byte, []int)

func (*CollarResponse) ProtoMessage

func (*CollarResponse) ProtoMessage()

func (*CollarResponse) Reset

func (m *CollarResponse) Reset()

func (*CollarResponse) String

func (m *CollarResponse) String() string

func (*CollarResponse) XXX_DiscardUnknown

func (m *CollarResponse) XXX_DiscardUnknown()

func (*CollarResponse) XXX_Marshal

func (m *CollarResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*CollarResponse) XXX_Merge

func (m *CollarResponse) XXX_Merge(src proto.Message)

func (*CollarResponse) XXX_Size

func (m *CollarResponse) XXX_Size() int

func (*CollarResponse) XXX_Unmarshal

func (m *CollarResponse) XXX_Unmarshal(b []byte) error

type CollarServer

type CollarServer interface {
	SendCommand(context.Context, *CollarRequest) (*CollarResponse, error)
}

CollarServer is the server API for Collar service.

type Sd400

type Sd400 struct {
	// contains filtered or unexported fields
}

func New

func New(remoteId string, rpitxPath string, wavOutputPath string) Sd400

func (*Sd400) Beep

func (s *Sd400) Beep(duration time.Duration)

Sends a beep command for the specified duration.

func (*Sd400) Nick

func (s *Sd400) Nick(level int)

func (*Sd400) SendCommand

func (s *Sd400) SendCommand(ctx context.Context, request *CollarRequest) (*CollarResponse, error)

func (*Sd400) Shock

func (s *Sd400) Shock(level int, duration time.Duration)

Sends a continuous stimulation command for the specified intensity and duration.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL