399 lines
12 KiB
C
399 lines
12 KiB
C
|
|
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <xPL.h>
|
|
#include <telldus-core.h>
|
|
|
|
#define TELLDUS_VERSION "1.0"
|
|
#define INSTANCE_MAX 16
|
|
|
|
static xPL_ServicePtr telldusService = NULL;
|
|
static Bool daemonMode = TRUE;
|
|
char hostname[INSTANCE_MAX];
|
|
|
|
void sendDevInfo(xPL_MessagePtr msg);
|
|
void sendDevList(xPL_MessagePtr msg);
|
|
void sendGatewayInfo();
|
|
void sendNetInfo(xPL_MessagePtr msg);
|
|
void sendNetList();
|
|
|
|
void lightingCommandHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue) {
|
|
Bool found = FALSE;
|
|
int deviceCount = 0, deviceId = 0, i, level = 0;
|
|
|
|
if (!xPL_doesMessageNamedValueExist(theMessage, "command")) {
|
|
return;
|
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "command"), "goto") != 0) {
|
|
return;
|
|
}
|
|
|
|
if (!xPL_doesMessageNamedValueExist(theMessage, "network")) {
|
|
return;
|
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "network"), "1") != 0) {
|
|
return;
|
|
}
|
|
|
|
if (!xPL_doesMessageNamedValueExist(theMessage, "device")) {
|
|
return;
|
|
} else {
|
|
/* Loop the devices to see it realy exists */
|
|
deviceCount = tdGetNumberOfDevices();
|
|
|
|
xPL_strToInt(xPL_getMessageNamedValue(theMessage, "device"), &deviceId);
|
|
for( i = 0; i < deviceCount; ++i ) {
|
|
if (tdGetDeviceId(i) == deviceId) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (found == FALSE) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!xPL_doesMessageNamedValueExist(theMessage, "level")) {
|
|
return;
|
|
} else {
|
|
xPL_strToInt(xPL_getMessageNamedValue(theMessage, "level"), &level);
|
|
if (level < 0 || level > 100) {
|
|
return;
|
|
}
|
|
level = (float)level * 255.0 / 100.0;
|
|
}
|
|
|
|
if (level > 0 && level < 255) {
|
|
/* See if the device supports dim */
|
|
if (!(tdMethods(deviceId, TELLSTICK_DIM) & TELLSTICK_DIM)) {
|
|
/* Non dimmable device was dimmed */
|
|
return;
|
|
}
|
|
tdDim(deviceId, (unsigned char)level);
|
|
} else if (level == 255) {
|
|
/* See if the device supports dim */
|
|
if (!(tdMethods(deviceId, TELLSTICK_TURNON) & TELLSTICK_TURNON)) {
|
|
/* Non dimmable device was dimmed */
|
|
return;
|
|
}
|
|
tdTurnOn(deviceId);
|
|
} else if (level == 0) {
|
|
/* See if the device supports dim */
|
|
if (!(tdMethods(deviceId, TELLSTICK_TURNOFF) & TELLSTICK_TURNOFF)) {
|
|
/* Non dimmable device was dimmed */
|
|
return;
|
|
}
|
|
tdTurnOff(deviceId);
|
|
}
|
|
|
|
}
|
|
|
|
void lightingRequestHandler(xPL_ServicePtr theService, xPL_MessagePtr theMessage, xPL_ObjectPtr userValue) {
|
|
|
|
if (!xPL_doesMessageNamedValueExist(theMessage, "request")) {
|
|
return;
|
|
}
|
|
|
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "devinfo") == 0) {
|
|
sendDevInfo(theMessage);
|
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "devlist") == 0) {
|
|
sendDevList(theMessage);
|
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "gateinfo") == 0) {
|
|
sendGatewayInfo();
|
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "netinfo") == 0) {
|
|
sendNetInfo(theMessage);
|
|
} else if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(theMessage, "request"), "netlist") == 0) {
|
|
sendNetList();
|
|
} else {
|
|
/* fprintf(stdout, "Request: %s\n", xPL_getMessageNamedValue(theMessage, "request")); */
|
|
}
|
|
}
|
|
|
|
void shutdownHandler(int onSignal) {
|
|
xPL_setServiceEnabled(telldusService, FALSE);
|
|
xPL_releaseService(telldusService);
|
|
xPL_shutdown();
|
|
exit(0);
|
|
}
|
|
|
|
void sendDevInfo(xPL_MessagePtr msg) {
|
|
xPL_MessagePtr message = NULL;
|
|
Bool found = FALSE, deviceCount = tdGetNumberOfDevices();
|
|
int deviceId = 0, methods = 0, i = 0, lastSentCommand, level = 0;
|
|
char *name, buffer[12], *value;
|
|
|
|
xPL_strToInt(xPL_getMessageNamedValue(msg, "device"), &deviceId);
|
|
for( i = 0; i < deviceCount; ++i ) {
|
|
if (tdGetDeviceId(i) == deviceId) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
|
xPL_setSchema(message, "lighting", "devinfo");
|
|
|
|
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
|
xPL_setMessageNamedValue(message, "device", xPL_getMessageNamedValue(msg, "device"));
|
|
|
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0 && found == TRUE) {
|
|
lastSentCommand = tdLastSentCommand(deviceId, TELLSTICK_TURNON | TELLSTICK_TURNOFF | TELLSTICK_DIM);
|
|
if (lastSentCommand == TELLSTICK_TURNON) {
|
|
level = 100;
|
|
} else if (lastSentCommand == TELLSTICK_DIM) {
|
|
value = tdLastSentValue(deviceId);
|
|
level = atoi(value);
|
|
free(value);
|
|
level = round((float)level / 255.0 * 100.0);
|
|
if (level > 100) {
|
|
level = 100;
|
|
} else if (level < 0) {
|
|
level = 0;
|
|
}
|
|
} else {
|
|
level = 0;
|
|
}
|
|
methods = tdMethods(deviceId, TELLSTICK_TURNON | TELLSTICK_TURNOFF | TELLSTICK_DIM);
|
|
name = tdGetName(deviceId);
|
|
sprintf(buffer, "1,%s,0,%i", (methods & TELLSTICK_DIM ? "true" : "false"), level);
|
|
xPL_setMessageNamedValue(message, "status", "ok");
|
|
xPL_setMessageNamedValue(message, "name", name );
|
|
xPL_setMessageNamedValue(message, "report-on-manual", "false" );
|
|
xPL_setMessageNamedValue(message, "channel-count", "1" );
|
|
xPL_setMessageNamedValue(message, "primary-channel", "1" );
|
|
xPL_setMessageNamedValue(message, "channel", buffer );
|
|
xPL_setMessageNamedValue(message, "scene-count", "0" );
|
|
|
|
free(name);
|
|
} else {
|
|
xPL_setMessageNamedValue(message, "status", "not-found");
|
|
}
|
|
|
|
xPL_sendMessage(message);
|
|
|
|
xPL_releaseMessage(message);
|
|
}
|
|
|
|
void sendDevList(xPL_MessagePtr msg) {
|
|
int deviceCount = 0, i;
|
|
char deviceList[128];
|
|
xPL_MessagePtr message = NULL;
|
|
|
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
|
xPL_setSchema(message, "lighting", "devlist");
|
|
|
|
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
|
|
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0) {
|
|
xPL_setMessageNamedValue(message, "status", "ok");
|
|
deviceCount = tdGetNumberOfDevices();
|
|
for( i = 0; i < deviceCount; ++i ) {
|
|
if (i == 0) { /* First */
|
|
strcpy(deviceList, xPL_intToStr(tdGetDeviceId(i)));
|
|
} else {
|
|
strcat(deviceList, ",");
|
|
strcat(deviceList, xPL_intToStr(tdGetDeviceId(i)));
|
|
}
|
|
}
|
|
|
|
xPL_setMessageNamedValue(message, "device-count", xPL_intToStr(deviceCount) );
|
|
xPL_setMessageNamedValue(message, "device", deviceList );
|
|
} else {
|
|
xPL_setMessageNamedValue(message, "status", "not-found");
|
|
}
|
|
|
|
xPL_sendMessage(message);
|
|
|
|
xPL_releaseMessage(message);
|
|
}
|
|
|
|
void sendGatewayInfo() {
|
|
xPL_MessagePtr message = NULL;
|
|
|
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
|
xPL_setSchema(message, "lighting", "gateinfo");
|
|
|
|
xPL_setMessageNamedValue(message, "status", "ok");
|
|
xPL_setMessageNamedValue(message, "protocol", "TELLDUS");
|
|
xPL_setMessageNamedValue(message, "description", "xPL to Telldus TellStick gateway");
|
|
xPL_setMessageNamedValue(message, "version", TELLDUS_VERSION);
|
|
xPL_setMessageNamedValue(message, "author", "Telldus Technologies AB");
|
|
xPL_setMessageNamedValue(message, "info-url", "http://www.telldus.se");
|
|
xPL_setMessageNamedValue(message, "net-count", "1");
|
|
xPL_setMessageNamedValue(message, "preferred-net", "1");
|
|
xPL_setMessageNamedValue(message, "scenes-ok", "false");
|
|
xPL_setMessageNamedValue(message, "channels-ok", "false");
|
|
xPL_setMessageNamedValue(message, "fade-rate-ok", "false");
|
|
|
|
/* Broadcast the message */
|
|
xPL_sendMessage(message);
|
|
|
|
xPL_releaseMessage(message);
|
|
}
|
|
|
|
void sendNetInfo(xPL_MessagePtr msg) {
|
|
xPL_MessagePtr message = NULL;
|
|
|
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
|
xPL_setSchema(message, "lighting", "netinfo");
|
|
|
|
xPL_setMessageNamedValue(message, "network", xPL_getMessageNamedValue(msg, "network"));
|
|
|
|
if (xPL_strcmpIgnoreCase(xPL_getMessageNamedValue(msg, "network"), "1") == 0) {
|
|
xPL_setMessageNamedValue(message, "status", "ok");
|
|
xPL_setMessageNamedValue(message, "name", hostname );
|
|
xPL_setMessageNamedValue(message, "device-count", xPL_intToStr(tdGetNumberOfDevices()) );
|
|
xPL_setMessageNamedValue(message, "scene-count", "0" );
|
|
} else {
|
|
xPL_setMessageNamedValue(message, "status", "not-found");
|
|
}
|
|
|
|
xPL_sendMessage(message);
|
|
|
|
xPL_releaseMessage(message);
|
|
}
|
|
|
|
void sendNetList() {
|
|
xPL_MessagePtr message = NULL;
|
|
|
|
message = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_STATUS);
|
|
xPL_setSchema(message, "lighting", "netlist");
|
|
|
|
xPL_setMessageNamedValue(message, "status", "ok");
|
|
xPL_setMessageNamedValue(message, "network", "1");
|
|
|
|
/* Broadcast the message */
|
|
xPL_sendMessage(message);
|
|
|
|
xPL_releaseMessage(message);
|
|
}
|
|
|
|
void sendGatewayReadyMessage() {
|
|
xPL_MessagePtr gatewayReadyMessage = NULL;
|
|
/* Create a message to send */
|
|
gatewayReadyMessage = xPL_createBroadcastMessage(telldusService, xPL_MESSAGE_TRIGGER);
|
|
xPL_setSchema(gatewayReadyMessage, "lighting", "gateway");
|
|
|
|
/* Install the value and send the message */
|
|
xPL_setMessageNamedValue(gatewayReadyMessage, "report", "gateway-ready");
|
|
|
|
/* Broadcast the message */
|
|
xPL_sendMessage(gatewayReadyMessage);
|
|
|
|
xPL_releaseMessage(gatewayReadyMessage);
|
|
}
|
|
|
|
/* parseCmdLine will handles command line switches. Valid switches are: */
|
|
/* -interface x - set interface to use */
|
|
/* -xpldebug - set debugging and enable xPL debugging */
|
|
/* -nodaemon - Dosn't disconnect from the console */
|
|
static Bool parseCmdLine( int *argc, char *argv[]) {
|
|
int swptr;
|
|
int newcnt = 0;
|
|
|
|
/* Handle each item of the command line. If it starts with a '-', then */
|
|
/* process it as a switch. If not, then copy it to a new position in */
|
|
/* the argv list and up the new parm counter. */
|
|
for(swptr = 0; swptr < *argc; swptr++) {
|
|
/* If it doesn't begin with a '-', it's not a switch. */
|
|
if (argv[swptr][0] != '-') {
|
|
if (swptr != newcnt) argv[++newcnt] = argv[swptr];
|
|
} else {
|
|
/* Check for daemon mode */
|
|
if (!strcmp(argv[swptr],"-nodaemon")) {
|
|
daemonMode = FALSE;
|
|
continue;
|
|
}
|
|
|
|
/* Anything left is unknown */
|
|
fprintf(stderr, "Unknown switch `%s'", argv[swptr] );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Set in place the new argument count and exit */
|
|
*argc = newcnt + 1;
|
|
return TRUE;
|
|
}
|
|
|
|
/* Print command usage info out */
|
|
void printUsage(String ourName) {
|
|
fprintf(stderr, "%s - Telldus TellStick xPL interface\n", ourName);
|
|
fprintf(stderr, "Copyright (c) 2009, Telldus Technologies AB\n\n");
|
|
fprintf(stderr, "Usage: %s [-xpldebug] [-nodaemon] [-ip x] [-interface x]\n", ourName);
|
|
fprintf(stderr, " -xpldebug -- enable xPLLib debugging messagaes\n");
|
|
fprintf(stderr, " -nodaemon -- don't detach -- run from the console\n");
|
|
fprintf(stderr, " -interface x -- Use interface named x (i.e. eth0) as network interface\n");
|
|
fprintf(stderr, " -ip x -- Bind to specified IP address for xPL\n");
|
|
}
|
|
|
|
void startServer() {
|
|
/* Initialze lighting service */
|
|
|
|
/* Create a service for us */
|
|
if (gethostname(hostname, INSTANCE_MAX) != 0) {
|
|
fprintf(stderr, "Unable to retrieve the hostname");
|
|
exit(1);
|
|
}
|
|
telldusService = xPL_createService("telldus", "core", hostname);
|
|
xPL_setServiceVersion(telldusService, TELLDUS_VERSION);
|
|
|
|
/* Add a responder */
|
|
xPL_addServiceListener(telldusService, lightingRequestHandler, xPL_MESSAGE_COMMAND, "lighting", "request", NULL);
|
|
xPL_addServiceListener(telldusService, lightingCommandHandler, xPL_MESSAGE_COMMAND, "lighting", "basic", NULL);
|
|
|
|
/* Install signal traps for proper shutdown */
|
|
signal(SIGTERM, shutdownHandler);
|
|
signal(SIGINT, shutdownHandler);
|
|
|
|
/* Enable the service */
|
|
xPL_setServiceEnabled(telldusService, TRUE);
|
|
sendGatewayReadyMessage();
|
|
|
|
for (;;) {
|
|
/* Let XPL run */
|
|
xPL_processMessages(-1);
|
|
}
|
|
}
|
|
|
|
int main(int argc, String argv[]) {
|
|
|
|
/* Parse command line parms */
|
|
if (!xPL_parseCommonArgs(&argc, argv, FALSE)) {
|
|
exit(1);
|
|
}
|
|
|
|
/* Start xPL up */
|
|
if (!xPL_initialize(xPL_getParsedConnectionType())) {
|
|
fprintf(stderr, "Unable to start xPL");
|
|
exit(1);
|
|
}
|
|
|
|
/* Parse Hub command arguments */
|
|
if (!parseCmdLine(&argc, argv)) {
|
|
printUsage(argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
if (daemonMode) {
|
|
switch (fork()) {
|
|
case 0: /* child */
|
|
/* No io in child mode */
|
|
close(fileno(stdin));
|
|
close(fileno(stdout));
|
|
close(fileno(stderr));
|
|
setpgrp();
|
|
|
|
startServer();
|
|
break;
|
|
case -1: /* error */
|
|
fprintf(stderr, "Unable to spawn daemon, %s (%d)\n", strerror(errno), errno);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
startServer();
|
|
}
|
|
return 0;
|
|
}
|
|
|