Skip to content

Commit

Permalink
MQTT and HTTP support. Moved old master to debian-stretch
Browse files Browse the repository at this point in the history
  • Loading branch information
jatocode committed Mar 21, 2023
1 parent be8b213 commit 52224ba
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 41 deletions.
30 changes: 23 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
# Branches

* master-branch will use a newer Ubuntu-version and "patch" telldus-core
* master is using Ubuntu 16.04 and has a simple MQTT and HTTP interface to access the tellstick with
* debian-stretch branch will use a newer Ubuntu-version and "patch" telldus-core
* xenial-branch uses Ubuntu 16.04 where telldus-core works without any special stuff

# Build

> docker build -t telldusdocker .
docker-compose build

# Start
# Run

> docker run --device=/dev/bus/usb/ -d telldusdocker
docker-compose up -d

OR more dangerously
> docker run --privileged -d telldusdocker

# Exec
# Execute tdtool inside the container from script or such

> docker exec -it "containerid" tdtool --list
# MQTT Interface

Edit config.json, enter a valid MQTT broker and topics to send/listen on
The toolname should be the name of the tool to call, most likely tdtool

The tellstick can be accessed in two ways via MQTT:

1. post to in-topic with payload like {"cmd":"--on","id":"1234"} or {"cmd":"--list"}
2. post to in-topic with path like /in/1234/on, /in/44/off or /in/list

# HTTP interface

VERY crude and simple. Configure a port in config.json and toolname
The tellstick can be accessed via:
GET http://localhost:port/api/device/1234/on or http://localhost:port/api/device/56/off

List devices is not yet supported
7 changes: 7 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"mqttserver":"mqtt://example.com",
"topic_in":"tellstick/in",
"topic_out":"tellstick/out",
"toolname":"tdtool",
"httpport":8080
}
15 changes: 15 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
version: "3"

services:
telldusdocker:
image: jatodocker/telldusdocker:2.3
build: .
ports:
- "8080:8080"
- "1993:1993"
devices:
- "/dev/bus/usb:/dev/bus/usb"
volumes:
- ./tellstick.conf:/etc/tellstick.conf
- ./config.json:/app/config.json
restart: unless-stopped
50 changes: 19 additions & 31 deletions dockerfile
Original file line number Diff line number Diff line change
@@ -1,46 +1,34 @@
FROM debian:stretch-slim
FROM ubuntu:xenial AS telldus

LABEL version="0.5"
LABEL description="Containerised telldus daemon för hemmabruk"
LABEL version="2.2"
LABEL description="Containerised telldus daemon. Answers on mqtt"
LABEL maintainer="[email protected]"

RUN apt-get update && apt-get upgrade -y && apt-get install curl gnupg -y
RUN apt-get update && apt-get upgrade -y ; \
apt-get install curl gnupg unzip dos2unix -y

# Add public key for telldus
RUN curl http://download.telldus.com/debian/telldus-public.key | apt-key add -

# Add source
RUN echo "deb http://download.telldus.com/debian/ stable main" >> /etc/apt/sources.list
RUN echo "deb http://download.telldus.com/debian/ stable main" >> /etc/apt/sources.list

# Baserat på:
# https://forum.telldus.com/viewtopic.php?f=8&t=4&p=49723&hilit=telldus+core+ubuntu&sid=55e6f99e8ed8d235aec93253a25213e6#p49723

# And install
RUN apt-get update && \
RUN apt-get update ; \
apt-get install -y --no-install-recommends \
libftdi1 \
libtelldus-core2

RUN apt-get download telldus-core

# Laddade ner de här manuellt
COPY libconfuse-common_3.2+really3.0+dfsg-1_all.deb libconfuse-common_3.2+really3.0+dfsg-1_all.deb
COPY libconfuse1_3.2+really3.0+dfsg-1_amd64.deb libconfuse1_3.2+really3.0+dfsg-1_amd64.deb

RUN dpkg -i libconfuse-common_3.2+really3.0+dfsg-1_all.deb && \
dpkg -i libconfuse1_3.2+really3.0+dfsg-1_amd64.deb && \
dpkg --ignore-depends=libconfuse0 -i telldus-core_2.1.2-1_amd64.deb
libftdi1 \
libtelldus-core2 \
telldus-core

RUN sed -i 's/\(Depends:.*\)libconfuse0[^,]*/\1libconfuse1 (>= 3.0)/' /var/lib/dpkg/status
RUN ln -s /usr/lib/x86_64-linux-gnu/libconfuse.so.1 /usr/lib/x86_64-linux-gnu/libconfuse.so.0
# Install deno runtime
RUN curl -fsSL https://deno.land/x/install/install.sh | sh

RUN apt-get --fix-broken install -y

RUN apt-mark hold libconfuse1 && apt-mark hold telldus-core
COPY tellstick.conf /etc/tellstick.conf
EXPOSE 1993
WORKDIR /app

COPY start_telldus.sh .
RUN chmod +x start_telldus.sh
COPY start.sh src/. ./
RUN /root/.deno/bin/deno cache main.ts

ENTRYPOINT ["./start_telldus.sh"]
RUN chmod +x start.sh && \
dos2unix start.sh

ENTRYPOINT ["./start.sh"]
Binary file removed libconfuse-common_3.2+really3.0+dfsg-1_all.deb
Binary file not shown.
Binary file removed libconfuse1_3.2+really3.0+dfsg-1_amd64.deb
Binary file not shown.
5 changes: 5 additions & 0 deletions src/IDevice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IDevice {
id:string,
name:string,
state:boolean
}
1 change: 1 addition & 0 deletions src/deps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Client } from 'https://deno.land/x/[email protected]/deno/mod.ts'
133 changes: 133 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { Client } from './deps.ts'
import PQueue from "https://deno.land/x/[email protected]/mod.ts"
import { serve } from "https://deno.land/[email protected]/http/server.ts";

import { IDevice } from './IDevice.ts'

// Expecting config.json with url to mqtt-server
const config = JSON.parse(await Deno.readTextFile("./config.json"));

const queue = new PQueue({
concurrency: 1,
})

async function main(serverurl: string, topic_in: string = 'tellstick', topic_out: string = 'tellstick/out', tool: string = 'tdtool') {

console.log(`Listening on ${serverurl}/${topic_in}/#, using ${tool} for exec`)

const client = new Client({
url: serverurl,
})

serve(httphandler, { port: config.httpport })

await client.connect()

const decoder = new TextDecoder()

client.on('message', async (topic: string, payload: Uint8Array) => {

if (payload.length > 0) {
// /tellstick/in {"cmd":"--on","id":"1234"}
const jsondata = decoder.decode(payload)
let data: any;
try {
data = JSON.parse(jsondata)
} catch (e) {
console.error('Failed to parse ', jsondata);
return;
}

switch (topic) {
case topic_in:
// Run shellcommand
await queue.add(() => runShellCommand(tool, data.cmd, data.id, topic_out, client))
break
default:
break
}
} else {
// /tellstick/in/1234/on or //tellstick/in/list

if (topic.startsWith(topic_in)) {
if (topic.endsWith('/list')) {
await queue.add(() => runShellCommand(tool, '--list', '0', topic_out, client))
} else {
const r = topic.split('/')
if (r.length == 4) {
const id = r[2]
const cmd = '--' + r[3]
// Run shellcommand
await queue.add(() => runShellCommand(tool, cmd, id, topic_out, client))
}
}
}
}
})

// Debug
// queue.addEventListener("idle", () => console.log("All done, no jobs in queue"))
// queue.addEventListener("active", () =>
// console.log(`Running queued cmd. Queue size: ${queue.size}`)
// )

await client.subscribe(`${topic_in}/#`)
}

// Run shellcommand function
async function runShellCommand(tool: string, cmd: string, id: string, topic_out: string, client: Client): Promise<boolean> {
console.log(`Running ${tool} with cmd:${cmd}, on id:${id}`)

const p = Deno.run({ cmd: [tool, cmd, id], stdout: 'piped', stderr: 'piped' })
const { code } = await p.status()

if (code == 0) {
const rawOutput = await p.output()
const decoder = new TextDecoder()
const output = decoder.decode(rawOutput);
if (cmd == '--list') {
let devices = await handleListCommand(output);
if(client && topic_out.length > 0)
await client.publish(topic_out, JSON.stringify(devices));
}
} else {
console.log(`${tool} exited with code ${code}`)
return false;
}

return true;
}

async function handleListCommand(cmdOutput: string): Promise<IDevice[]> {
let devices = [];
for (const row of cmdOutput.split('\n')) {
let m = row.match(/(\d+)\t(.*)\t(OFF|ON)/);
if (m && m.length > 0) {
let device: IDevice = {
id: m[1],
name: m[2],
state: m[3] == 'ON'
};
devices.push(device);
}
}

return devices;
}

async function httphandler(req: Request): Promise<Response> {
const url = new URL(req.url);

// /api/device/1234/on
const match = url.pathname.match(/\/api\/device\/(\d+)\/(on|off)/);
if (match && match.length > 0) {
const id = match[1]
const cmd = '--' + match[2]
await queue.add(() => runShellCommand(config.toolname, cmd, id, '', null))
}

return new Response("OK");
}

main(config.mqttserver, config.topic_in, config.topic_out, config.toolname)

4 changes: 4 additions & 0 deletions start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#! /bin/sh

/usr/sbin/telldusd 2> /var/log/telldus.log --nodaemon &
/root/.deno/bin/deno run --allow-read --allow-net --allow-run main.ts
3 changes: 0 additions & 3 deletions start_telldus.sh

This file was deleted.

0 comments on commit 52224ba

Please sign in to comment.