---
# System prepended metadata

title: TSL2561
tags: [raspberry pi, hardware, pigpio, python]

---

# TSL2561
###### tags: `raspberry pi` `hardware` `python` `pigpio`
## Wiring
address : 0x39
| TSL2561 | Raspberry Pi |
| ------- | ------------ |
| VCC     | 3.3V         |
| GND     | 0V           |
| SCL     | GPIO03 SCL1  |
| SDA     | GPIO02 SDA1  |
| INT     | None         |
## Program
### smbus
```python=
import smbus

# initialize
print("initialize")
bus = smbus.SMBus(1) # bus number 1
address = 0x39 # tsl2561 address
bus.write_byte_data(address, 0x80, 0x03) # power on
bus.write_byte_data(address, 0x81, 0x12) # initialize flag (0b00010010)

# read
data0 = bus.read_i2c_block_data(address , 0x8c, 2) #ch0
data1 = bus.read_i2c_block_data(address , 0x8e, 2) #ch1
ch0 = data0[1] << 8 | data0[0]
ch1 = data1[1] << 8 | data1[0]
print(f"channel 0 : {ch0}")
print(f"channel 1 : {ch1}")
result = 1.0 * ch1 / ch0
print(f"result : {result}")
if 0 < result <= 0.5:
    lux = 0.0304 * ch0 - 0.062 * ch0 * (result ** 1.4)
elif 0.5 < result <= 0.61:
    lux = 0.0224 * ch0 - 0.031 * ch1
elif 0.61 < result <= 0.8:
    lux = 0.0128 * ch0 - 0.0153 * ch1
elif 0.8 < result <= 1.3:
    lux = 0.0146 * ch0 - 0.00112 * ch1
else:
    lux = 0
print(f"lux : {round(lux, 2)}")
```
### pigpio
```python=
"""
TSL2561を制御するモジュール
"""
from enum import Flag, auto
from time import sleep
import pigpio


class TSL2561Gain(Flag):
    """
    TSL2561の利得を表す型
    """

    high = auto()
    low = auto()


class TSL2561Integral(Flag):
    """
    TSL2561の積層時間を表す型
    """

    high = auto()
    medium = auto()
    low = auto()


class TSL2561:
    """
    デジタル温度センサTSL2561を扱うためのクラス
    Attributes
    ----------
    address: int, default 0x39
        TSL2561のI2Cアドレス
    flag: int, default 0
        I2C通信のフラグ
    gain: TSL2561Gain, default TSL2561Gain.high
        TSL2561の利得
    integral: TSL2561Integral, default TSL2561Integral.high
        TSL2561の積分時間
    """

    def __init__(self, pi: pigpio.pi) -> None:
        """
        Parameters
        ----------
        pi: pigpio.pi
            pigpioデーモンと通信するためのオブジェクト
        """
        self.address: int = 0x39
        self.flag: int = 0
        self.gain: TSL2561Gain = TSL2561Gain.high
        self.integral: TSL2561Integral = TSL2561Integral.high
        if not pi.connected:
            raise pigpio.error(pigpio.error_text(-1))
        self._hndl: int
        self._pi: pigpio.pi = pi

    def _get_gain(self) -> int:
        """
        TSL2561IntegralからI2Cで送る利得の値を取得する関数
        Returns
        -------
        integral: int
            I2Cで送る利得の値
        """
        if self.gain == TSL2561Gain.low:
            gain = 0b0
        elif self.gain == TSL2561Gain.high:
            gain = 0b1
        return gain << 4

    def _get_integral(self) -> int:
        """
        TSL2561IntegralからI2Cで送る積分時間の値を取得する関数
        Returns
        -------
        integral: int
            I2Cで送る積分時間の値
        """
        if self.integral == TSL2561Integral.low:
            integral = 0b00
        elif self.integral == TSL2561Integral.medium:
            integral = 0b01
        elif self.integral == TSL2561Integral.high:
            integral = 0b10
        return integral

    def initialize(self, bus: int) -> None:
        """
        TSL2561の初期化
        Parameters
        ----------
        bus: int
            使用するI2Cバス
        """
        self._hndl = self._pi.i2c_open(bus, self.address, self.flag)
        self._pi.i2c_write_byte_data(self._hndl, 0x80, 0x03)
        mode = self._get_gain() | self._get_integral()
        self._pi.i2c_write_byte_data(self._hndl, 0x81, mode)
        sleep(1)
        _ = self.read_illuminance()

    def finalize(self) -> None:
        """TSL2561の後処理"""
        self._pi.i2c_close(self._hndl)
        del self._hndl

    def read_illuminance(self) -> float:
        """
        照度を取得
        Returns
        -------
        lux: float
            取得した照度
        """
        count, adc = self._pi.i2c_read_i2c_block_data(self._hndl, 0x8C, 4)
        if count < 0:
            raise pigpio.error(pigpio.error_text(count))
        ch0 = (adc[1] << 8) + adc[0]
        ch1 = (adc[3] << 8) + adc[2]
        try:
            result = 1.0 * ch1 / ch0
        except ZeroDivisionError:
            result = 0.0
        if result <= 0:
            lux = 0.0
        elif result <= 0.5:
            lux = 0.0304 * ch0 - 0.062 * ch0 * (result ** 1.4)
        elif result <= 0.61:
            lux = 0.0224 * ch0 - 0.031 * ch1
        elif result <= 0.8:
            lux = 0.0128 * ch0 - 0.0153 * ch1
        elif result <= 1.3:
            lux = 0.0146 * ch0 - 0.00112 * ch1
        else:
            lux = 0.0
        if self.gain == TSL2561Gain.low:
            lux *= 16
        if self.integral == TSL2561Integral.low:
            lux *= 29.343
        elif self.integral == TSL2561Integral.medium:
            lux *= 3.98
        return lux


def main():
    """
    main function for test
    """
    pi_daemon = pigpio.pi()
    tsl2561 = TSL2561(pi_daemon)
    tsl2561.initialize(1)
    lux = tsl2561.read_illuminance()
    print(f"Illuminance : {lux}")
    tsl2561.finalize()
    pi_daemon.stop()


if __name__ == "__main__":
    main()
```
## Refarence
[datasheet](https://cdn-shop.adafruit.com/datasheets/TSL2561.pdf)
[qiita](https://qiita.com/aike@github/items/1c27438846f31670d38f)
[5\$](https://www.denshi.club/pc/raspi/5raspberry-pi-zeroiot27-1-i2c-tls2561.html)
