# GhostSensor Thermal by Forrest
# Some code from Adafruit's tutorials at:
### https://learn.adafruit.com/adafruit-1-44-color-tft-with-micro-sd-socket
### https://learn.adafruit.com/adafruit-amg8833-8x8-thermal-camera-sensor
import math
import time
import digitalio
import numpy as np
import board
from PIL import Image, ImageDraw, ImageFont
from adafruit_rgb_display import st7735
from scipy.interpolate import griddata
import RPi.GPIO as io

from colour import Color

import adafruit_amg88xx

i2c = board.I2C()
io.setup(12, io.OUT)
io.setup(19, io.OUT)
io.setup(13, io.OUT)
io.setup(6, io.OUT)
io.setup(5, io.OUT)
io.output(12, True)
io.output(19, False)
io.output(13, False)
io.output(6, False)
io.output(5, False)


# Configuration for CS and DC pins (these are PiTFT defaults):
cs_pin = digitalio.DigitalInOut(board.CE0)
dc_pin = digitalio.DigitalInOut(board.D25)
reset_pin = digitalio.DigitalInOut(board.D24)

# Config for display baudrate (default max is 24mhz):
BAUDRATE = 24000000

# Setup SPI bus using hardware SPI:
spi = board.SPI()

disp = st7735.ST7735R(spi, rotation=180, height=128, x_offset=2, y_offset=3,
    cs=cs_pin,
    dc=dc_pin,
    rst=reset_pin,
    baudrate=BAUDRATE,
)

height = 128
width = 128

image = Image.new("RGB", (width, height))

# low range of the sensor (this will be blue on the screen)
MINTEMP = 26
# high range of the sensor (this will be red on the screen)
MAXTEMP = 30.0

# how many color values we can have
COLORDEPTH = 1024

# initialize the sensor
sensor = adafruit_amg88xx.AMG88XX(i2c)

# pylint: disable=invalid-slice-index
points = [(math.floor(ix / 8), (ix % 8)) for ix in range(0, 64)]
grid_x, grid_y = np.mgrid[0:7:32j, 0:7:32j]
# pylint: enable=invalid-slice-index

# sensor is an 8x8 grid so lets do a square
draw = ImageDraw.Draw(image)
draw.rectangle((0, 0, width, height), outline=0, fill=(0, 0, 0))
disp.image(image)

# the list of colors we can choose from
blue = Color("indigo")
colors = list(blue.range_to(Color("red"), COLORDEPTH))

# create the array of colors
colors = [(int(c.red * 255), int(c.green * 255), int(c.blue * 255)) for c in colors]

displayPixelWidth = 4
displayPixelHeight = 4

# some utility functions
def constrain(val, min_val, max_val):
    return min(max_val, max(min_val, val))


def map_value(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min


# let the sensor initialize
time.sleep(0.1)

while True:

    # read the pixels
    pixels = []
    for row in sensor.pixels:
        pixels = pixels + row
    pixels = [map_value(p, MINTEMP, MAXTEMP, 0, COLORDEPTH - 1) for p in pixels]
    valm = np.mean(sensor.pixels)

    if valm <= 23:
        io.output(19, False)
        io.output(13, False)
        io.output(6, False)
        io.output(5, False)
    elif valm <= 24 and valm > 23:
        io.output(19, True)
        io.output(13, False)
        io.output(6, False)
        io.output(5, False)
    elif valm <= 25 and valm > 24:
        io.output(19, True)
        io.output(13, True)
        io.output(6, False)
        io.output(5, False)
    elif valm <= 26 and valm > 25:
        io.output(19, True)
        io.output(13, True)
        io.output(6, True)
        io.output(5, False)
    elif valm > 25:
        io.output(19, True)
        io.output(13, True)
        io.output(6, True)
        io.output(5, True)

    # perform interpolation
    bicubic = griddata(points, pixels, (grid_x, grid_y), method="cubic")

    # draw everything
    for ix, row in enumerate(bicubic):
        for jx, pixel in enumerate(row):
            col_t = colors[constrain(int(pixel),0,COLORDEPTH-1)]
            draw.rectangle((displayPixelWidth * jx,displayPixelHeight * ix,
            (displayPixelWidth * jx) + 4,(displayPixelHeight * ix) + 4), outline=col_t, fill=col_t)

    disp.image(image)
    time.sleep(.1)
