• 10 dec 2017: forum version update. In case of issues use this topic.
  • 30 nov 2017: pilight moved servers. In case of issues use this topic.
Hello There, Guest! Login Register


TSL2561 i2c digital illuminance sensor
#1
Lightbulb 
Hi,
here is the support for the TSL2561 illuminance sensor from Rohm (datasheet -> link).

My sourcecode is not the perfect one, but it works :

tsl2561.h
Code:
#ifndef _PROTOCOL_TSL2561_H_
#define _PROTOCOL_TSL2561_H_

#include "../protocol.h"

struct protocol_t *tsl2561;
void tsl2561Init(void);

#endif


// this is a example sourcecode/header from the datasheet
//****************************************************************************
//
// Copyright 2004-2005 TAOS, Inc.
//
// THIS CODE AND INFORMATION IS PROVIDED AS IS WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
//****************************************************************************
#define LUX_SCALE 14 // scale by 2^14
#define RATIO_SCALE 9 // scale ratio by 2^9
//---------------------------------------------------
// Integration time scaling factors
//---------------------------------------------------
#define CH_SCALE 10 // scale channel values by 2^10
#define CHSCALE_TINT0 0x7517 // 322/11 * 2^CH_SCALE
#define CHSCALE_TINT1 0x0fe7 // 322/81 * 2^CH_SCALE
//---------------------------------------------------
// T, FN, and CL Package coefficients
//---------------------------------------------------
#define K1T 0x0040 // 0.125 * 2^RATIO_SCALE
#define B1T 0x01f2 // 0.0304 * 2^LUX_SCALE
#define M1T 0x01be // 0.0272 * 2^LUX_SCALE
#define K2T 0x0080 // 0.250 * 2^RATIO_SCALE
#define B2T 0x0214 // 0.0325 * 2^LUX_SCALE
#define M2T 0x02d1 // 0.0440 * 2^LUX_SCALE
#define K3T 0x00c0 // 0.375 * 2^RATIO_SCALE
#define B3T 0x023f // 0.0351 * 2^LUX_SCALE
#define M3T 0x037b // 0.0544 * 2^LUX_SCALE
#define K4T 0x0100 // 0.50 * 2^RATIO_SCALE
#define B4T 0x0270 // 0.0381 * 2^LUX_SCALE
#define M4T 0x03fe // 0.0624 * 2^LUX_SCALE
#define K5T 0x0138 // 0.61 * 2^RATIO_SCALE
#define B5T 0x016f // 0.0224 * 2^LUX_SCALE
#define M5T 0x01fc // 0.0310 * 2^LUX_SCALE
#define K6T 0x019a // 0.80 * 2^RATIO_SCALE
#define B6T 0x00d2 // 0.0128 * 2^LUX_SCALE
#define M6T 0x00fb // 0.0153 * 2^LUX_SCALE
#define K7T 0x029a // 1.3 * 2^RATIO_SCALE
#define B7T 0x0018 // 0.00146 * 2^LUX_SCALE
#define M7T 0x0012 // 0.00112 * 2^LUX_SCALE
#define K8T 0x029a // 1.3 * 2^RATIO_SCALE
#define B8T 0x0000 // 0.000 * 2^LUX_SCALE
#define M8T 0x0000 // 0.000 * 2^LUX_SCALE
//---------------------------------------------------
// CS package coefficients
//---------------------------------------------------
#define K1C 0x0043 // 0.130 * 2^RATIO_SCALE
#define B1C 0x0204 // 0.0315 * 2^LUX_SCALE
#define M1C 0x01ad // 0.0262 * 2^LUX_SCALE
#define K2C 0x0085 // 0.260 * 2^RATIO_SCALE
#define B2C 0x0228 // 0.0337 * 2^LUX_SCALE
#define M2C 0x02c1 // 0.0430 * 2^LUX_SCALE
#define K3C 0x00c8 // 0.390 * 2^RATIO_SCALE
#define B3C 0x0253 // 0.0363 * 2^LUX_SCALE
#define M3C 0x0363 // 0.0529 * 2^LUX_SCALE
#define K4C 0x010a // 0.520 * 2^RATIO_SCALE
#define B4C 0x0282 // 0.0392 * 2^LUX_SCALE
#define M4C 0x03df // 0.0605 * 2^LUX_SCALE
#define K5C 0x014d // 0.65 * 2^RATIO_SCALE
#define B5C 0x0177 // 0.0229 * 2^LUX_SCALE
#define M5C 0x01dd // 0.0291 * 2^LUX_SCALE
#define K6C 0x019a // 0.80 * 2^RATIO_SCALE
#define B6C 0x0101 // 0.0157 * 2^LUX_SCALE
#define M6C 0x0127 // 0.0180 * 2^LUX_SCALE
#define K7C 0x029a // 1.3 * 2^RATIO_SCALE
#define B7C 0x0037 // 0.00338 * 2^LUX_SCALE
#define M7C 0x002b // 0.00260 * 2^LUX_SCALE
#define K8C 0x029a // 1.3 * 2^RATIO_SCALE
#define B8C 0x0000 // 0.000 * 2^LUX_SCALE
#define M8C 0x0000 // 0.000 * 2^LUX_SCALE

tsl2561.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifndef _WIN32
    #ifdef __mips__
        #define __USE_UNIX98
    #endif
#endif
#include <pthread.h>

#include "../../core/pilight.h"
#include "../../core/common.h"
#include "../../core/dso.h"
#include "../../core/log.h"
#include "../../core/threads.h"
#include "../../core/binary.h"
#include "../../core/gc.h"
#include "../../core/json.h"
#ifndef _WIN32
    #include "../../../wiringx/wiringX.h"
#endif
#include "../protocol.h"
#include "tsl2561.h"

#if !defined(__FreeBSD__) && !defined(_WIN32)
typedef struct settings_t {
    char **id;
    int nrid;
    int *fd;
} settings_t;

static unsigned short loop = 1;
static int threads = 0;

static pthread_mutex_t lock;
static pthread_mutexattr_t attr;

// this is a example sourcecode from the datasheet
unsigned int CalculateLux(unsigned int iGain, unsigned int tInt, unsigned int ch0,unsigned int ch1, int iType)
{
    unsigned long chScale;
    unsigned long channel1;
    unsigned long channel0;
    switch (tInt)
    {
    case 0: // 13.7 msec
        chScale = CHSCALE_TINT0;
        break;
    case 1: // 101 msec
        chScale = CHSCALE_TINT1;
        break;
    default: // assume no scaling
        chScale = (1 << CH_SCALE);
        break;
    }

    if (!iGain) chScale = chScale << 4;

    channel0 = (ch0 * chScale) >> CH_SCALE;
    channel1 = (ch1 * chScale) >> CH_SCALE;

    unsigned long ratio1 = 0;
    if (channel0 != 0)
    ratio1 = (channel1 << (RATIO_SCALE+1)) / channel0;

    unsigned long ratio = (ratio1 + 1) >> 1;

    unsigned int b, m;
    switch (iType)
    {
    case 0: // T, FN and CL package
        if ((ratio >= 0) && (ratio <= K1T))
        {b=B1T; m=M1T;}
        else if (ratio <= K2T)
            {b=B2T; m=M2T;}
        else if (ratio <= K3T)
            {b=B3T; m=M3T;}
        else if (ratio <= K4T)
            {b=B4T; m=M4T;}
        else if (ratio <= K5T)
            {b=B5T; m=M5T;}
        else if (ratio <= K6T)
            {b=B6T; m=M6T;}
        else if (ratio <= K7T)
        {b=B7T; m=M7T;}
        else if (ratio > K8T)
            {b=B8T; m=M8T;}
        break;
    case 1:// CS package
        if ((ratio >= 0) && (ratio <= K1C))
            {b=B1C; m=M1C;}
        else if (ratio <= K2C)
            {b=B2C; m=M2C;}
        else if (ratio <= K3C)
            {b=B3C; m=M3C;}
        else if (ratio <= K4C)
            {b=B4C; m=M4C;}
        else if (ratio <= K5C)
            {b=B5C; m=M5C;}
        else if (ratio <= K6C)
            {b=B6C; m=M6C;}
        else if (ratio <= K7C)
            {b=B7C; m=M7C;}
        else if (ratio > K8C)
        {b=B8C; m=M8C;}
        break;
    }

    unsigned long temp;
    temp = ((channel0 * b) - (channel1 * m));

    if (temp < 0) temp = 0;

    temp += (1 << (LUX_SCALE-1));

    unsigned long lux = temp >> LUX_SCALE;

    return(lux);
}


static void *thread(void *param) {
    struct protocol_threads_t *node = (struct protocol_threads_t *)param;
    struct JsonNode *json = (struct JsonNode *)node->param;
    struct JsonNode *jid = NULL;
    struct JsonNode *jchild = NULL;
    struct settings_t *tsl2561data = MALLOC(sizeof(struct settings_t));
    int y = 0, interval = 10, nrloops = 0 ;
    int ch0 = 0, ch1 = 0;
    int lux = 0 , ptype = 0;
    char *stmp = NULL;
    double itmp = -1 ;

    if(tsl2561data == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(EXIT_FAILURE);
    }

    tsl2561data->nrid = 0;
    tsl2561data->id = NULL;
    tsl2561data->fd = 0;

    threads++;

    if((jid = json_find_member(json, "id"))) {
        jchild = json_first_child(jid);
        while(jchild) {
            if(json_find_string(jchild, "id", &stmp) == 0) {
                if((tsl2561data->id = REALLOC(tsl2561data->id, (sizeof(char *)*(size_t)(tsl2561data->nrid+1)))) == NULL) {
                    fprintf(stderr, "out of memory\n");
                    exit(EXIT_FAILURE);
                }
                if((tsl2561data->id[tsl2561data->nrid] = MALLOC(strlen(stmp)+1)) == NULL) {
                    fprintf(stderr, "out of memory\n");
                    exit(EXIT_FAILURE);
                }
                strcpy(tsl2561data->id[tsl2561data->nrid], stmp);
                tsl2561data->nrid++;
            }
            jchild = jchild->next;
        }
    }

    if(json_find_number(json, "poll-interval", &itmp) == 0)
        interval = (int)round(itmp);

    if(json_find_number(json, "packagetype", &itmp) == 0)
        ptype = (int)round(itmp);

    if((tsl2561data->fd = REALLOC(tsl2561data->fd, (sizeof(int)*(size_t)(tsl2561data->nrid+1)))) == NULL) {
        fprintf(stderr, "out of memory\n");
        exit(EXIT_FAILURE);
    }

    for(y=0;y<tsl2561data->nrid;y++) {
        tsl2561data->fd[y] = wiringXI2CSetup((int)strtol(tsl2561data->id[y], NULL, 16));
    }

    while(loop) {
        if(protocol_thread_wait(node, interval, &nrloops) == ETIMEDOUT) {
            pthread_mutex_lock(&lock);
            for(y=0;y<tsl2561data->nrid;y++) {
                if(tsl2561data->fd[y] > 0) {
                    wiringXI2CWriteReg8(tsl2561data->fd[y],0x80,0x03);
                    wiringXI2CWriteReg8(tsl2561data->fd[y],0x81,0x02);
                    usleep (0.403 * 1000000);
                    ch0 = wiringXI2CReadReg16(tsl2561data->fd[y], 0xac);
                    ch1 = wiringXI2CReadReg16(tsl2561data->fd[y], 0xae);
                    wiringXI2CWriteReg8(tsl2561data->fd[y],0x80,0x00);
                    lux = CalculateLux(0, 2, ch0, ch1, ptype);

                    tsl2561->message = json_mkobject();
                    JsonNode *code = json_mkobject();
                    json_append_member(code, "id", json_mkstring(tsl2561data->id[y]));
                    json_append_member(code, "illuminance", json_mknumber(lux, 0));
                    json_append_member(tsl2561->message, "message", code);
                    json_append_member(tsl2561->message, "origin", json_mkstring("receiver"));
                    json_append_member(tsl2561->message, "protocol", json_mkstring(tsl2561->id));

                    if(pilight.broadcast != NULL) {
                        pilight.broadcast(tsl2561->id, tsl2561->message, PROTOCOL);
                    }
                    json_delete(tsl2561->message);
                    tsl2561->message = NULL;
                } else {
                    logprintf(LOG_NOTICE, "error connecting to tsl2561");
                    logprintf(LOG_DEBUG, "(probably i2c bus error from wiringXI2CSetup)");
                    logprintf(LOG_DEBUG, "(maybe wrong id? use i2cdetect to find out)");
                    protocol_thread_wait(node, 1, &nrloops);
                }
            }
            pthread_mutex_unlock(&lock);
        }
    }
    pthread_mutex_unlock(&lock);

    if(tsl2561data->id) {
        for(y=0;y<tsl2561data->nrid;y++) {
            FREE(tsl2561data->id[y]);
        }
        FREE(tsl2561->id);
    }
    if(tsl2561data->fd) {
        for(y=0;y<tsl2561data->nrid;y++) {
            if(tsl2561data->fd[y] > 0) {
                close(tsl2561data->fd[y]);
            }
        }
        FREE(tsl2561data->fd);
    }
    FREE(tsl2561data);
    threads--;

    return (void *)NULL;
}

static struct threadqueue_t *initDev(JsonNode *jdevice) {
    if(wiringXSupported() == 0 && wiringXSetup() == 0) {
        loop = 1;
        char *output = json_stringify(jdevice, NULL);
        JsonNode *json = json_decode(output);
        json_free(output);

        struct protocol_threads_t *node = protocol_thread_init(tsl2561, json);
        return threads_register("tsl2561", &thread, (void *)node, 0);
    } else {
        return NULL;
    }
}

static void threadGC(void) {
    loop = 0;
    protocol_thread_stop(tsl2561);
    while(threads > 0) {
        usleep(10);
    }
    protocol_thread_free(tsl2561);
}


#endif

#if !defined(MODULE) && !defined(_WIN32)
__attribute__((weak))
#endif
void tsl2561Init(void) {
#if !defined(__FreeBSD__) && !defined(_WIN32)
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&lock, &attr);
#endif

    protocol_register(&tsl2561);
    protocol_set_id(tsl2561, "tsl2561");
    protocol_device_add(tsl2561, "tsl2561", "TAOS I2C illuminance sensor");
    tsl2561->devtype = WEATHER;
    tsl2561->hwtype = SENSOR;
    
    options_add(&tsl2561->options, 'i', "id", OPTION_HAS_VALUE, DEVICES_ID, JSON_STRING, NULL, "0x[0-9a-fA-F]{2}");
    options_add(&tsl2561->options, 'e', "illuminance", OPTION_HAS_VALUE, DEVICES_VALUE, JSON_NUMBER, NULL, "^[0-9]{1}$");
    options_add(&tsl2561->options, 0, "packagetype", OPTION_HAS_VALUE, DEVICES_SETTING, JSON_NUMBER, (void *)0, "^[10]{1}$");
    options_add(&tsl2561->options, 0, "poll-intervall", OPTION_HAS_VALUE, DEVICES_SETTING, JSON_NUMBER, (void *)10, "[0-9]");
    options_add(&tsl2561->options, 0, "show-illuminance", OPTION_HAS_VALUE, GUI_SETTING, JSON_NUMBER, (void *)1, "^[10]{1}$");

#if !defined(__FreeBSD__) && !defined(_WIN32)
    tsl2561->initDev=&initDev;
    tsl2561->threadGC=&threadGC;
#endif
}

#if defined(MODULE) && !defined(_WIN32)
void compatibility(struct module_t *module) {
    module->name = "tsl2561";
    module->version = "1.0";
    module->reqversion = "7.0";
    module->reqcommit = "1";
}

void init(void) {
    tsl2561Init();
}
#endif

config.json / device
Code:
"lux": {
            "protocol": [ "tsl2561" ],
            "id": [{
                "id": "0x39"
            }],
            "illuminance": 10000
        }

the sensor is working now. If you want to switch a light on in the evening/darkness, fix the tsl2561 to your window to the outside and setup a rule :

config.json / rule
Code:
"rules": {
        "dark": {
            "rule": "IF lux.illuminance < 500 THEN switch DEVICE lamp TO on",
            "active": 1
        }

The illuminance value is my example, please use pilight-receive to look the actual value and determine your personal switching threshold.

greetz
Marc
 
Reply
#2
Could you share compiled TSL2561.so
 
Reply
#3
Can you open a pull request on the pilight GitHub with this protocol addition? Then it is easier to review the code and eventually integrate your code into pilight.

(Please read the contributing.md first though to allow for a smooth process Wink)
 
Reply
#4
I tried to do it but I did not quit.
I have some errors
 
Reply
#5
(11-29-2016, 06:30 PM)kniazio Wrote: I have some errors
...such as? Please share the full error messages as well as the steps you took so that somebody can help. It's hard to know where the problem is right now Smile
 
Reply
#6
(11-29-2016, 06:04 PM)pilino1234 Wrote: Can you open a pull request on the pilight GitHub with this protocol addition? Then it is easier to review the code and eventually integrate your code into pilight.

(Please read the contributing.md first though to allow for a smooth process Wink)

done...https://github.com/pilight/pilight/pull/308

greetz
Marc
 
Reply
#7
Can not you add these sensors to pilight nightly?
I do not know how to add these protocols, and the rest is my pilight.
 
Reply
#8
(11-29-2016, 06:18 AM)kniazio Wrote: Could you share compiled TSL2561.so

see attachment


Attached Files
.zip   tsl2561.zip (Size: 6.3 KB / Downloads: 4)
 
Reply
#9
Thanks.
 
Reply
#10
Updated to the current development branch (libwiringx update)

config.json (devices section)

Code:
        "S_tsl": {
            "protocol": [ "tsl2561" ],
            "id": [{
                "id": "0x39",
                "i2c-path": "/dev/i2c-1"
            }],
            "poll-interval": 60,
            "illuminance": 19490
        }

see attached module


Attached Files
.zip   tsl2561.zip (Size: 6.51 KB / Downloads: 3)
 
Reply
  


Possibly Related Threads...
Thread Author Replies Views Last Post
Lightbulb [Fully Supported] Kaku Door sensor (AMST-606) geerttttt 52 23,812 10-12-2019, 06:57 PM
Last Post: curlymo
  Digoo / Baldr / Nexus / Rubicson temperature/humidity sensor thielj 4 1,234 09-30-2019, 04:48 PM
Last Post: curlymo
  433MHz PIR sensor from Amazon ha_username 0 42 09-29-2019, 11:44 PM
Last Post: ha_username
  gs-iwds07 window sensor Loggisch 46 12,291 01-02-2019, 09:11 PM
Last Post: curlymo
  Pearl weatherstation sensor for FWS-686 & FWS-665 chklump 13 4,487 08-12-2018, 05:34 PM
Last Post: fourty2
  TFA 30.3160 Pool Sensor wseifert 4 862 05-30-2018, 09:24 AM
Last Post: wseifert
Lightbulb BH1750 i2c digital illuminance sensor marcm 14 3,466 02-25-2018, 08:40 PM
Last Post: morph027
  [Fully Supported] LM75 and LM76 temperature sensor horst_dieter 64 24,709 11-19-2017, 08:54 PM
Last Post: edepi
  Air Pollution Data Sensor Alex 0 839 08-07-2017, 06:26 AM
Last Post: Alex
  eTiger Contact Sensor (ES-D3C) Terra 0 1,061 02-02-2017, 03:25 AM
Last Post: Terra

Forum Jump:


Browsing: 1 Guest(s)