Kotinäyttö VANHA VERSIO

PenaPedia
Versio hetkellä 13. joulukuuta 2024 kello 12.34 – tehnyt 192.168.0.104 (keskustelu) (VANHAT LÖYTYI,ARKISTOIDAAN)
(ero) ← Vanhempi versio | Nykyinen versio (ero) | Uudempi versio → (ero)
Siirry navigaatioonSiirry hakuun


Löysin sittenkin sattumalta vanhan version. Huhhuh, otetaan sekin nyt esille tänne. En tiedä toimiiko se suoriltaan ja miten hyvin mutta lähinnä tuon muuttuvan liittymätehon palkin kaipasin mielelläni takaisin, koska siinä olikin hieman pähkäilyä.

Jatkamme silti uuden kehittämistä, tästä saadaan vain hyvää mallia jos tarvitsee luntata. Rakenteellisesti tuo on aivan hirveä eikä sitä kannata käyttää kuin korkeintaan viitteellisenä mallina

  • Sähkön hinnan haku ei ainakaan toimi, vaan jos sellaista tarvii, tulee käyttää myöhemmin julkaistavan kunnollisen version funktioita

Kotinäyttö

Pääsivu, täällä jalostetaan uusinta versiota.

PALVELINPUOLI

import RPi.GPIO as GPIO
import time, sys
import http.server
from http.server import BaseHTTPRequestHandler, HTTPServer
import socketserver
import _thread
import threading
import socket
from socketserver import ThreadingMixIn
import requests, json
import datetime
import array as arr
import statistics
import time
import json
import pprint
import math
import os
import ADS1x15
from timeit import Timer
from numpy import log as ln
from urllib.parse import unquote


paivaHinta = 4.08 + ((2.79372 + 0.22) * 1.24)
yoHinta = 2.67 + ((2.79372 + 0.22) * 1.24)
varaajan_last_timestamp = 0


sahkonKiinteaOsa = {toFixed
    0 : yoHinta,
    1 : yoHinta,
    2 : yoHinta,
    3 : yoHinta,
    4 : yoHinta,
    5 : yoHinta,
    6 : yoHinta,
    7 : paivaHinta,
    8 : paivaHinta,
    9 : paivaHinta,
    10: paivaHinta,
    11: paivaHinta,
    12: paivaHinta,
    13: paivaHinta,
    14: paivaHinta,
    15: paivaHinta,
    16: paivaHinta,
    17: paivaHinta,
    18: paivaHinta,
    19: paivaHinta,
    20: paivaHinta,
    21: paivaHinta,
    22: yoHinta,
    23: yoHinta
}


data = {
        'sahko_hinta_tanaan'             :  [0 for i in range(25)] ,
        'sahko_hinta_huomenna'           :  [0 for i in range(25)] ,
        'kulutus_spot'                   :  [0],
        'spot_kulutus_hinta'             :  [0],
        'kumul_spot_kokonaishinta'        :  0,
        'kumul_kokonaiskulutus'          :  0,
        'kumul_pulssit'                  :  0,
        'elspot_alv'                     : 1.24, #HOX Nordpoolin hinnat ovat verottomia. HOX ALV lasketaan verottomasta hinnasta ;)
        'elspot_marginaali'              : 0.01,
        'piirturi_sahko'                 :  [0],
        'piirturi_pulssit'               : 0,
        'piirturi_count'                 : 1000, #Piirturi aloittaa seuraavasta tasa-vartista
        'siirtoHintaYosahkolla'          : 0,
        'varaajan_kayntitunnit'          : [0],
        'currentHour'                    : 0,
        'sahko' :  {'pulsseja_laskettu'  : 0,
                    'pulssien_vali'      : 10,
                    'pulssien_otanta'    : 5,
                    'realTimeMonitorLog' : [0],
                    'pulssit_yo'         : 0,
                    'pulssit_paiva'      : 0,
                    'lastTimestamp'      : 0,
                    'pulsseja_per_kwh'   : 10000,    # yes, Mäntsälän Sähkö aivilon have 10 000 blinks per kWh ;)
                    'kulutusTunneittain' : [0 for i in range(24)],
                    'hintaTunneittain'   : [0 for i in range(24)],
                    'varaajan_tarve'     : [0] 
                    },
        'kv'    :   {'pulsseja_laskettu' : 0,       #Täysin turha homma mutta en mene nyt sorkkimaan sitä
                     'vetta_kulunut'     : 0,
                     'pulssien_vali'     : 0
                    },
        'meta'  :   {'saikeitaKaynnissa' : 0,
                     'asiakkaitaPaikalla': 0,
                     'data_tumple_size'  : 44,  #Mikshän tuo on noin ?? Kysyisin itseltäin
                     'broadcastedBytes'  : 0,
                     'nordpoolReqTimes'  : 0,
                     'httpPyyntojaSaatu' : 0,
                     'allowNordpoolReq'  : 1,   #Vahditaan hieman ettei ala spämmiä Nordpooliin. Kerran jo pelastikin kun tein virheen koodiin
                     'paivamaaraTanaan'  : datetime.datetime.today().strftime("%d-%m-%Y"),
                     'restartTimes'      : 0,
                     'ajoaikaSec'        : 0,
                     'tuntilaskuri'      : 0,
                     'datadumppiLuotu'   : time.time()
                    },
        'vesi' :    {'taajuus'                   : 0,
                     'lastTimestamp'             : 0,
                     'ulkokierto_count'          : 0,
                     'kierron_lammitysteho'      : 0, 
                     'kierron_saasto'            : 0,
                     'kylma_vesi_c'              : 5, #kaivoveden lämpötila, lämmitystehon laskua varten TÄTÄ ARVOA EI VOI MUUTTAA JÄLKEENPÄIN, ei vaikuta takautuvasti lukemiin TODO: Hommaa mittari tohon
                     'kylma_vesi_taajuus'        : 0,
                     'kylma_vesi_lastTimestamp'  : 0,
                     'kylma_vesi_count'          : 0,
                     'varaajan_kapasiteetti'     : 99000, # 99000 pulssia mittarilta = 150 litraa,
                     'varaajan_havioteho'        : 0.1,  # kW  
                     'varaajan_lammitysteho'     : 1.92,   # kW
                     'varaajan_status'           : 99000, # Lähtötilanne = täynnä
                     'varaajan_status_esilam'    : 99000, # Varaajan latausaste lasketaan myös huomioiden veden esilämmitys
                     'varaajan_pakotus'          : False  # True = pinout lähtö on silloin 0, avautuva kosketin ohjaa kontaktorin kelaa
                    },
        'vesi_logi': { 'kylma_paivittain'         : [0],         #HOX tätä ei striimata livenä, eritelty siksi veden alaisuudesta pois
                       'lammin_paivittain'        : [0],
                       'ponton_lampotila'         : [0],
                       'kierron_menolampo'        : [0],
                       'kierron_paluulampo'       : [0]
                     },
        'ilp':       { 'ilp_count_per_h'          : [0],
                       'ilp_count'                : 0,
                       'ilp_teho'                 : 0,
                       'ilp_delay'                : 0,
                       'ulkolampo'                : [0],    # Näiden logituksen pituudesta päättää siivooja()
                       'sisalampo'                : [0],
                       'parvi'                    : [0],
                       'sisa_puhallus'            : [0],
                       'ilp_ottoteho_log'         : [0],
                       'wc_lampo'                 : [0],
                       'varaajain_lampo'          : [0],
                       'lastTimestamp'            : 0,
                       'tuuletin_auto'            : 0,
                       'tuuletin_pwm'             : 0,
                       'tuuletin_parametrit'      : 'sp1_c=1 sp1_kW=0.3 sp2_c=2 sp2_kW=0.7 poissa=0 '
                    },
        'lastLogs' : [0] 
                        
    }
#Tossa on niin vitusti kaikkea turhaa etten ole edes itsekään enään perillä kaikesta
# Vesimittarien kertoimet 1/2 = 11 ja 3/4 = 6.6

devices = {
        'huone'             : '/sys/bus/w1/devices/28-3cf5f648648b/w1_slave',
        'parvi'             : '/sys/bus/w1/devices/28-3c05f6482521/w1_slave',
        'ulko'              : '/sys/bus/w1/devices/28-3c03f648e6af/w1_slave',
        'sisa_puhallus'     : '/sys/bus/w1/devices/28-3ca9f648c262/w1_slave',
        'kierron_meno'      : '/sys/bus/w1/devices/28-3ce10457c47b/w1_slave',
        'kierron_paluu'     : '/sys/bus/w1/devices/28-3ce1045723c3/w1_slave',
        'ponton_lampotila'  : '/sys/bus/w1/devices/28-3ce10457e032/w1_slave'
}
ilpOttotehoAwg = [1]


def varaajan_hoitaja():
    global data
    varaajan_hallinta('varaaja_paalle')
    return 0
    
    #hinnat_tanaan = hae_sahkonhinta()
    hinnat_tanaan = data['sahko_hinta_tanaan']
    
    tunti = int(((datetime.datetime.today()).strftime('%-H')))
    
    kaytettavatHinnat = []
    
    #Kopioidaan taulukko, otetaan huomioon vain tästä tunnista eteenpäin hinnat,viimeinen indeksi on pvm sitä ei otetea
    kaytettavatHinnat = data['sahko_hinta_tanaan'][tunti:-1].copy() 
    print(type(kaytettavatHinnat))
    print(type(data['sahko_hinta_huomenna']))
     #Onko huomisen hintoja vielä tullut   
    if data['sahko_hinta_huomenna'][0] != 0:
        hinnat_huomenna = data['sahko_hinta_huomenna'][-2]
        kaytettavatHinnat.append(hinnat_huomenna)

    print(data['sahko_hinta_huomenna'])

    
    print("TUNTI NAYTTAA: " + str(tunti))
    summaaja = 0

    #my_list = [float(i) for i in my_list]

    ka = math.fsum(map(float, kaytettavatHinnat)) / len(kaytettavatHinnat)#Keskiarvo kaikista tulevista hinnoista
    
    #Muutetaan varaajan kapasiteetti ja latausaste kilowateiksi:
    data['sahko']['varaajan_tarve'] = ((data['vesi']['varaajan_kapasiteetti'] / 60 / 11) * 80 * 4.2) / 3600 - ((data['vesi']['varaajan_status'] / 60 / 11) * 80 * 4.2) / 3600
    logi("Varaajan lämmitystarve: " + str(data['sahko']['varaajan_tarve']))
    #Käyntitunnit kerrotaan lämmitysteholla, jotta saadaan oikea lukema esim. 2 kW teholla tunnissa varaaja latautuu 2 kW/h       
    kayntitunnit = []
    

            
    print("KÄYTETTÄVÄT HINNAT: " + str(kaytettavatHinnat))
    #Lasketaan montako tuntia voidaan pitää varaajaa päällä raaoilla hintarajoilla
    #Esim aina päällä jos kokonaishinta on alle 10 cnt
    for i in range(len(kaytettavatHinnat)):        
        if kaytettavatHinnat[i] < 8.5:               
            print("Päällä: tunti = " + str(i + tunti) + " hinnalla: " + str(kaytettavatHinnat[i]))
            kayntitunnit.append((tunti + i))
            continue
        if kaytettavatHinnat[i] < min(kaytettavatHinnat) * 1.15: 
            print("Päällä: tunti = " + str(i + tunti) + " hinnalla: " + str(kaytettavatHinnat[i]))
            kayntitunnit.append((tunti + i))
            continue

    
    
    #Toinen kierros, sallitaan kalliimpia hintoja jos varaajan kilowattitarve on kasvanut
    for i in range(len(kaytettavatHinnat)):
        if (tunti + i) in kayntitunnit:               #Skippaa tunnit jotka on jo raaoilla arvoilla
            #print("Skipataan tunti: " + str(i))
            i = i+1
            continue
        #Jos varaajan lämmöntarve on suurempi kuin hinnaston ka. sallitaan lämmitystunti
        #hinnalla joka on max. 50 % kaikkien hintojen keskiarvosta
        if (len(kayntitunnit) * data['vesi']['varaajan_lammitysteho'] ) < data['sahko']['varaajan_tarve'] and kaytettavatHinnat[i] < ka * 0.3:
            print("min + 30 % tunti = " + str(i) + " hinnalla: " + str(kaytettavatHinnat[tunti + i]))
            kayntitunnit.append(i + tunti)
            continue
        if (len(kayntitunnit) * data['vesi']['varaajan_lammitysteho'] ) < data['sahko']['varaajan_tarve'] and kaytettavatHinnat[i] < ka * 0.5:
            print("min + 50 % tunti = " + str(i) + " hinnalla: " + str(kaytettavatHinnat[int(tunti + i)]))
            kayntitunnit.append(i + tunti)
            continue
        #Jos ei edellinenkään riitä, sallitaan varaajan käynnistyä max. keskiarvon hintaisilla tunneilla
        if (len(kayntitunnit) * data['vesi']['varaajan_lammitysteho'] ) < data['sahko']['varaajan_tarve'] and kaytettavatHinnat[i] < ka:
            print("KA hinnalla: tunti = " + str(tunti + i) + " hinnalla: " + str(kaytettavatHinnat[int(tunti + i)]))
            kayntitunnit.append(i + tunti)
            continue
        if (len(kayntitunnit) * data['vesi']['varaajan_lammitysteho'] ) < data['sahko']['varaajan_tarve'] and kaytettavatHinnat[i] < ka * 1.2:
            print("KA + 20% tunti = " + str(tunti + i) + " hinnalla: " + str(kaytettavatHinnat[int(tunti + i)]))
            kayntitunnit.append(i + tunti)
            continue


    if data['vesi']['varaajan_pakotus'] == True:
        logi("Varaajan hoitaja kirjaa tämän tunnin päällepakotetuksi")
        kayntitunnit.append(tunti)
        logi("Varaajan hoitaja kirjasi tunti nro: " + str(tunti) + " päällepakotetuksi")
    
    logi(str(kaytettavatHinnat))
    data['varaajan_kayntitunnit'] = kayntitunnit

def varaajan_hallinta(arg):
    global data, varaajan_last_timestamp
    
    #Aina pitää olla kulunut 60 * 2 sekunttia ennen kuin varaajan kärkitilaa voi muuttaa
    if arg == 'varaaja_paalle' and (time.time() - varaajan_last_timestamp) > 60 * 2:
        varaajan_last_timestamp = time.time()
        logi("Varaaja käynnistettiin!")
        GPIO.output(25, 1)
        return 0
    return 0
    if arg == 'sammuta_varaaja' and (time.time() - varaajan_last_timestamp) > 60 * 2:
        varaajan_last_timestamp = time.time()
        GPIO.output(25, 0)
        logi("Varaaja sammutettiin!")
        return 0
    logi("***** VARAAJAN HALLINNAN KUMPIKAAN EHTO EI TOTEUTUNUT ******")
    logi("AIKA-ARVO: " + str(time.time() - varaajan_last_timestamp))
    logi("***************")


def parsi_lampotila(lines): #Palauttaa arvon 0, jos lämpöä ei mistä tahansa syystä saada
        

    if lines == False or len(lines) != 2:
        ##logi("parsi_lampotila: EI PARSITTAVAA")
        print(lines)
        return 0
    logi("parsi_lampotila() : " + str(lines))
    if (lines[0][-4 : len(lines[0])-1]) != 'YES':
        logi("parsi_lampotila: TEMP IS NOT VALID")
        logi("txt")
        return 0
    #print(lines[0][-3 : len(lines[0])])
    return round(int(lines[1][lines[1].find("t=")+2:len(lines[1])]) / 1000, 1)


def lue_anturi (device):
    ##logi("AVATAAN LAITE: " + device)
    time.sleep(1)
    try:
        with open(device, 'r') as onewire:
            time.sleep(0.5)
            lines = onewire.readlines()
            onewire.close()
    except:
        logi("lue_anturi: EI LÖYDY LAITETIEDOSTOA")
        logi("lue_anturi: " + device)
        time.sleep(1)
        return parsi_lampotila(False)
    return parsi_lampotila(lines)
    
def tuulettimen_ohjaus():
    #data['ilp']['tuuletin_parametrit'] = 'sp1_c=1 sp1_kW=0.3 sp2_c=3 sp2_kW=0.7'
    logi("Tuulettimen parametrit: " + data['ilp']['tuuletin_parametrit'])
    nopeudet = (dict(s.split('=', 1) for s in data['ilp']['tuuletin_parametrit'].split()))
    
    lampotilaero = data['ilp']['parvi'][-1] - data['ilp']['sisalampo'][-1]
    logi("Lampotilaero: " + str(lampotilaero))
    if int(nopeudet['poissa']) == 1:
        GPIO.output(21, 1)
        GPIO.output(20, 0)
        logi("Puhaltimen pieni nopeus - poissa = 1")
        return 0
    if lampotilaero > float(nopeudet['sp2_c']) or data['ilp']['ilp_teho'] > float(nopeudet['sp2_kW']): #Suurin nopeus
        GPIO.output(21, 0)
        time.sleep(1)
        GPIO.output(21, 1)
        GPIO.output(20, 1)
        logi("Puhaltimen suuri nopeus")
        return 0
    if lampotilaero > float(nopeudet['sp1_c']) or data['ilp']['ilp_teho'] > float(nopeudet['sp1_kW']):  #Toisiksi suurin nopeus
        GPIO.output(21, 1)
        GPIO.output(20, 0)
        logi("Puhaltimen pieni nopeus")
        return 0
    GPIO.output(21, 0) #Puhallin kiinni, jos päästään tänne asti
    logi("GPIO: 21 = 0, puhallin kiinni")
    return 0
        

def siivooja(): #Poistetaan tarpeeksi vanhat lukemat
    global data
    if len(data['ilp']['sisalampo']) > 1440:         #1440 min == 24 h
        data['ilp']['sisalampo'].pop(0)
    if len(data['ilp']['ulkolampo']) > 1440:
        data['ilp']['ulkolampo'].pop(0)
    if len(data['ilp']['parvi']) > 1440:
        data['ilp']['parvi'].pop(0)
    if len(data['ilp']['sisa_puhallus']) > 1440:
        data['ilp']['sisa_puhallus'].pop(0)
    if len(data['ilp']['ilp_ottoteho_log']) > 1440:
        data['ilp']['ilp_ottoteho_log'].pop(0)
    if len(data['lastLogs']) > 20:                  #Rivien määrä
        data['lastLogs'].pop(0)
    if len(data['kulutus_spot']) > 48:              #Sähkön kulutus, tunneittain
        data['kulutus_spot'].pop(0)
    if len(data['ilp']['ilp_count_per_h']) > 24*7*31: #ILP kulutus, tunneittain
        data['ilp']['ilp_count_per_h'].pop(0)
    if len(data['sahko']['realTimeMonitorLog']) > 50:   #Hetkellinen kulutus, rivien määrä
        data['sahko']['realTimeMonitorLog'].pop(0)
    if len(data['vesi_logi']['kierron_paluulampo']) > 1440:
        data['vesi_logi']['kierron_paluulampo'].pop(0)
    if len(data['vesi_logi']['ponton_lampotila']) > 1440:
        data['vesi_logi']['ponton_lampotila'].pop(0)
    if len(data['vesi_logi']['kierron_menolampo']) > 1440:
        data['vesi_logi']['kierron_menolampo'].pop(0)
    
    
class handler(BaseHTTPRequestHandler):
    global tuloste
    def do_OPTIONS(self):
        self.send_response(200)
        self.send_header("Access-Control-Allow-Origin", "*")
        #self.send_header("Access-Control-Allow-Credentials", "true")
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept")  
        self.end_headers()
    def do_GET(self):
        data['meta']['httpPyyntojaSaatu'] += 1
        logi("GEttiä kutsutaan!")
        if '?tuuletin_parametrit' in self.path:
            data['ilp']['tuuletin_parametrit'] = unquote(self.path.split('?tuuletin_parametrit')[1])
            logi("Uudet parametrit: " + data['ilp']['tuuletin_parametrit'])
        if self.path.endswith('/kaikki_data'): #Lähettää koko data arrayn json dumppina
            self.send_response(200)
            self.send_header("Access-Control-Allow-Origin", "*")
            #self.send_header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Origin, Accept") 
            self.send_header('Content-type', 'application/json')
            self.end_headers()
            output = str.encode(json.dumps(data))
            data['meta']['broadcastedBytes'] += len(output)
            self.wfile.write(output)
            logi("/kaikki_data tarjoiltu")
            return
            logi("yhteys ei katkea")
        elif self.path.endswith('/debug'):
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            output = ""
            output += pprint.pformat(data, indent=1,sort_dicts=False) #Prints multidimensional array or list very very pretty - with tabs and <br>s on browser. Fucking hard find this on simple without anything functions or loops
            self.wfile.write(str.encode(output))
            return
        elif self.path.endswith('/pakota_varaaja_paalle'):
            self.send_response(200)
            self.send_header('Content-type', 'text/plain')
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            if data['vesi']['varaajan_pakotus'] == False:
                data['vesi']['varaajan_pakotus'] = True
            else:
                data['vesi']['varaajan_pakotus'] = False
            return
        elif self.path.endswith('/etusivu.html'):
            self.send_response(200)
            self.send_header('Content-type', 'text/html; charset=UTF-8')
            self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            f = open("etusivu.html", "r")
            output = f.read()
            f.close()
            data['meta']['broadcastedBytes'] += len(output)
            self.wfile.write(str.encode(output))
            return
        elif self.path.endswith('/livestream'):
            data['meta']['asiakkaitaPaikalla'] += 1
            #Soketti pidetään auki jatkuvasti ja lähetetään selaimelle SSE tyylillä *** MUISTA ALKUUN 'data: ' teksti ja loppuun KAKSI rivinvaihtoa
            self.send_response(200)
            self.send_header("Access-Control-Allow-Origin", "*")
            #self.send_header("Access-Control-Allow-Credentials", "true")
            self.send_header('Cache-Control:', 'no-cache')
            self.send_header('Content-type', 'text/event-stream')
            self.end_headers()
            edellinen_lastLog = 0
            lastHourDateTime = int(((datetime.datetime.today()-datetime.timedelta(hours = 1)).strftime('%-H')))
            while True: #Valikoitua dataa lähetetään sekunnin välein selaimelle
                lastLog = 0
                if data['lastLogs'][len(data['lastLogs']) - 1] != edellinen_lastLog: #Ei lähetetä samaa lastlogia uudestaan
                    lastLog = data['lastLogs'][len(data['lastLogs']) - 1]
                edellinen_lastLog = data['lastLogs'][len(data['lastLogs']) - 1]
                tunti = int(((datetime.datetime.today()).strftime('%-H')))
                output = ('data: ' + json.dumps({
                                                'realTimeMonitorLog'   : data['sahko']['realTimeMonitorLog'][ len(data['sahko']['realTimeMonitorLog']) - 1 ],
                                                'meta'                 : data['meta'],
                                                'lastLogs'             : lastLog,
                                                'pulsseja_laskettu'    : sum(data['sahko']['kulutusTunneittain']),
                                                'kumul_spot_kokonaishinta' : data['kumul_spot_kokonaishinta'] + (data['piirturi_pulssit'] * ( 1 / data['sahko']['pulsseja_per_kwh'])) * data['sahko_hinta_tanaan'][tunti],
                                                'vesi'                 : data['vesi'],
                                                'ilp_count'            : data['ilp']['ilp_count'] + sum(data['ilp']['ilp_count_per_h']),
                                                'ilp_teho'             : data['ilp']['ilp_teho'],
                                                'ulkolampo'            : data['ilp']['ulkolampo'][-1],
                                                'sisalampo'            : data['ilp']['sisalampo'][-1],
                                                'parvi'                : data['ilp']['parvi'][-1],
                                                'sisa_puhallus'        : data['ilp']['sisa_puhallus'][-1],
                                                'varaajan_karkitieto'  : int(GPIO.input(25)),              #Varaaja sammuu, kun relepaketti vetää
                                                'pulssit_paiva'        : data['sahko']['pulssit_paiva'],
                                                'pulssit_yo'           : data['sahko']['pulssit_yo'],
                                                'piirturi_pulssit'     : data['piirturi_pulssit'],
                                                'sahkon_hinta_nyt'     : data['sahko_hinta_tanaan'][tunti],
                                                'kuluva_tunti'         : tunti,
                                                'vesi_ulkokierto_meno' : data['vesi_logi']['kierron_menolampo'][-1],
                                                'vesi_ulkokierto_tmp'  : data['vesi_logi']['kierron_paluulampo'][-1],
                                                'vesi_ponton_tmp'      : data['vesi_logi']['ponton_lampotila'][-1]
                                                })
                                                + "\n\n")
                output = str.encode(output)
                data['meta']['broadcastedBytes'] += len(output)
                try:
                     self.wfile.write(output)
                except:
                    logi("SOKETTI TAISI KATKETA")
                    data['meta']['asiakkaitaPaikalla'] -= 1
                    return
                #print(output)
                time.sleep(1)
            logi("YHTEYS KATKESI")
            
        else:
            self.send_response(404)
            #self.send_header("Access-Control-Allow-Origin", "*")
            self.end_headers()
            output = "<h1>ETUSIVU</h1>"
            self.wfile.write(str.encode(output))
            
    print("TÄnne ei pitäisi päästä")    #Joskus tänne pääsee silti :O

def kodin_hengetar():

    logi("Kodin hengetär täällä!")
    global data, f, devices, ilpOttotehoAwg
    #testi = 0
    ulkokierto_count_temp = 0
    kierronSaastoTemp = time.time()                                     #TÄMÄ RIVI ON VAIN MUUTTUJAN KERTALUONTEINEN ALUSTUS
    #print(data['sahkon_hinta_tanaan'])
    while True:
        ulkokierto_count_temp = data['vesi']['ulkokierto_count']        # Heti alussa talteen nykyhetken mittarilukema
        pysayta_mittari()
        time.sleep(1)
        #data['meta']['paivamaaraTanaan'] = datetime.datetime.today().strftime("%d-%m-%Y")
        data['meta']['data_tumple_size'] = sys.getsizeof(data)

        if data['meta']['paivamaaraTanaan'] != datetime.datetime.today().strftime("%d-%m-%Y"):
            #testi = 0
            logi("PAIVA VAIHTUI")
            data['vesi_logi']['kylma_paivittain'].append((data['vesi']['kylma_vesi_count'] / 6.6) / 60)
            data['vesi']['kylma_vesi_count'] = 0
            data['vesi_logi']['lammin_paivittain'].append((data['vesi']['ulkokierto_count'] / 11) / 60)
            data['vesi']['ulkokierto_count'] = 0
            data['meta']['paivamaaraTanaan'] = datetime.datetime.today().strftime("%d-%m-%Y")
        
        #testi += 1
        if data['meta']['nordpoolReqTimes'] > 500:    #Turvafeature, ettei syystä tai toisesta virhetilanteessa ala mennä spämmiä nordpooliin pyyntöjä
            data['meta']['allowNordpoolReq'] = 0
            logi("NORDPOOL = 0")
            return 0
        
        if data['sahko_hinta_tanaan'][24] != datetime.datetime.today().strftime('%d-%m-%Y') and data['meta']['allowNordpoolReq'] == 1:
            #Viimeinen indeksi on päivämäärä ^^
            logi("Haetaan tämän päivän sähkön hinta (sahkon_hinta_tanaan 24 = " + str(data['sahko_hinta_tanaan'][24]))
            data['sahko_hinta_tanaan'] = hae_sahkonhinta(data['meta']['paivamaaraTanaan']).copy()

            logi("Haettiin tämän päivän sähkönhinta")
            logi(data['sahko_hinta_tanaan'][24])
            data['sahko_hinta_huomenna'] = [0 for i in range(25)]
            
        huominen = (datetime.datetime.today()+datetime.timedelta(days=+1)).strftime('%d-%m-%Y')
        if data['sahko_hinta_huomenna'][24] != huominen and int(time.strftime("%H")) > 14 and data['meta']['allowNordpoolReq'] == 1:

            logi("Haetaan huomisen sähkön hinnat:")
            
            data['sahko_hinta_huomenna'] = hae_sahkonhinta(huominen).copy()
            logi("HAETTIIN HUOMISEN HINNAT")
        

        data['meta']['saikeitaKaynnissa'] = threading.active_count()
        
        laske_sahkon_kulutus()
        
        ilpOttotehoAwg.append(data['ilp']['ilp_teho']) #Joka sekuntti lisätään sen hetken spot teho
        if len(ilpOttotehoAwg) > 60:                    #Pidetään n. minuutin mittaista rullaavaa listaa
            ilpOttotehoAwg.pop(0)
        
        #data['vesi']['kierron_paluulampo'] = mittaa_lampotila()

        #data['vesi']['kierron_lammitysteho'] = (((data['vesi']['taajuus'] / 11)/60) * (data['vesi']['kierron_paluulampo'] - data['vesi']['kylma_vesi_c']) * 4.2)  #4.2 = veden ominaislämpökapasiteetti
        #Kaava benchmnarkattu ^^
        
        ##### VARAAJAN HOITO ####
        data['vesi']['varaajan_status'] -= data['vesi']['ulkokierto_count'] - ulkokierto_count_temp     # Vähennetään varaajan statuksesta kierroksen aikana käytetty vesimäärä

        if data['vesi']['varaajan_status'] > data['vesi']['varaajan_kapasiteetti']:                     # Varaaja on täynnä, tämä ettei varaajan_status ylitäyty
            data['vesi']['varaajan_status'] = data['vesi']['varaajan_kapasiteetti']
            logi("Varaaja on täynnä")
        if (data['vesi']['varaajan_status'] < 500):
            #Varaajan status ei voi mennä nollaan tai negatiiviseksi
            logi("Varaajan_status lähestyy nollaa!")
            logi("Muutetaan statukseksi 5000")
            data['vesi']['varaajan_status'] = 5000
        #data['vesi']['kierron_saasto'] += (data['vesi']['kierron_lammitysteho'] / (3600 / (time.time() - kierronSaastoTemp)))
        siivooja()
        kierronSaastoTemp = time.time() #Tästä saadaan aika kauanko yhteen kierrokseen menee (sek) TÄMÄN PITÄÄ OLLA VIIMEISENÄ


    logi("Kodin hengetär loppu")


def hearthbeat(): #Kutsutaan kerran minuutissa tekemään jotain hanttihommia
    global data, devices, ilpOttotehoAwg
    #if int(((datetime.datetime.today()).strftime('%S'))) % 60 == 0:
    offset_aika = time.time()
    odotusaika = 60
    if 1:
        logi(" *** Hearthbeat ***")
        #logi("LUETAAN HUONE:")
        data['ilp']['sisalampo'].append(lue_anturi(devices['huone']))
        #logi("LUETAAN ULKO:")
        data['ilp']['ulkolampo'].append(lue_anturi(devices['ulko']))
        #logi("LUETAAN PARVI: ")
        data['ilp']['parvi'].append(lue_anturi(devices['parvi']))
        #logi("LUETAAN SISA_PUHALLUS: ")
        data['ilp']['sisa_puhallus'].append(lue_anturi(devices['sisa_puhallus']))
        data['vesi_logi']['kierron_paluulampo'].append(lue_anturi(devices['kierron_paluu']))
        data['vesi_logi']['ponton_lampotila'].append(lue_anturi(devices['ponton_lampotila']))
        data['vesi_logi']['kierron_menolampo'].append(lue_anturi(devices['kierron_meno']))
        
        #Käynnistyksessä kaatuu, kun tapahtuu nollalla jako ilman tätä ehtoa

        data['ilp']['ilp_ottoteho_log'].append(float(f"{sum(ilpOttotehoAwg) / len(ilpOttotehoAwg):.3f}"))     #keskiarvo sekunneittain mitatusta ottotehosta
        
        ###VARAAJA / MINUUTEITTAIN TEHTÄVÄT TOIMET ####
        #Pakotusta ei laiteta päälle automaattisesti tyhjentyessä, jos varaaja on jo - syystä tai toisesta valmiiksi päällä
        if (data['vesi']['varaajan_status'] / data['vesi']['varaajan_kapasiteetti']) * 100 < 15 and GPIO.input(25) == 0:
            data['vesi']['varaajan_pakotus'] = True
            logi("Varaajan päällepakotusehto täyttyi!")
        
        
        
        if data['vesi']['varaajan_pakotus'] == True:           # Jos varaaja on pakotettu päälle
            varaajan_hallinta("varaaja_paalle")
            logi("Varaaja on pakotettuna päälle")
            time.sleep(1)
        if GPIO.input(25) == 1:                               #Lisätään lämpöä vain, jos varaajan kela vetää. Tämä ehto toimii irrallaan kaikesta muusta
            heatDiff = 85 - data['vesi']['kylma_vesi_c']      #Veden lämpötilan nousun määrä asteina kaivokylmästä
            heatPulsesPerMin = ((data['vesi']['varaajan_lammitysteho'] * 60) / heatDiff / 4.2) * 11 * 60
            #Muunnos (kW --> Wh) / montako pulssia X lämpöistä vettä tulee Y teholla 60 sek aikana
            data['vesi']['varaajan_status'] += heatPulsesPerMin     #Lisätään varaajaan lämmintä
        
        #Varaajasta poistetaan aina häviö, tilasta riippumatta, ennalta määritetyllä teholla:
        data['vesi']['varaajan_status'] -= ((data['vesi']['varaajan_havioteho'] * 60) / (85 - 20) / 4.2) * 11 * 60  #Häviöteho, montako litraa lämmitetään 85 - huonelämpö, minuutin aikana X teholla
        #Montako pulssia (litraa) status laskee X häviöteholla, lämpötilaeron ollessa Y
        #Memo: ajattele asiaa näin: "montako litraa vettä lämpenee esim. 60 astetta tietyllä teholla MINUUTIN AIKANA" --> saat litramäärän --> muuta se vielä pulssien lukumääräksi vesimittarin kertoimella (11)
        data['vesi']['varaajan_status_esilam'] -= ((data['vesi']['varaajan_havioteho'] * 60) / (85 - 20) / 4.2) * 11 * 60  #Häviöteho, montako litraa lämmitetään 85 - huonelämpö, minuutin aikana X teholla

        
        
        #if (data['vesi']['varaajan_status'] / data['vesi']['varaajan_kapasiteetti']) * 100 < 30 and GPIO.input(25) == 0:
            #Jos varaajan status on alle X % JA varaaja ei vielä ole päällä (päiväsaika), pakotetaan se päälle automaattisesti
            #Tämän ehdon ei pitäisi toteutua yöllä - kärkitila on silloin 1 - varaaja on jo valmiiksi päällä
            #data['vesi']['varaajan_pakotus'] = True
            #logi("Varaaja pakotettiin automaattisesti päälle!")
        
        varaajan_hoitaja()
        
        
        #tuulettimen_ohjaus()
        
        

        try:
            with open("demofile3.txt", "w") as f:
                f.write(json.dumps(data))
                f.close()
        except:
            logi("HEARTHBEAT EI ONNISTUNUT TALLENNUKSESSA")
    logi("Hearthbeat - Kutsutaan laskuria: ")
    odotusaika = 60 - (round(time.time() - offset_aika))        #Vähennetään minuutin odotusajasta näihin kulunut aika
    if odotusaika < 10:
        logi("ODOTUSAIKA ALLE 10 SEK")
    t = threading.Timer(odotusaika, hearthbeat)
    t.start()


def hae_sahkonhinta(paiva = datetime.date.today().strftime('%d-%m-%Y')):
    global data, sahkonKiinteaOsa
    data['meta']['nordpoolReqTimes'] += 2
    hinnat = [0 for i in range(25)] #Viimeinen indeksi on päivämäärä
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.84 Safari/537.36'}

    osoite = "http://www.nordpoolgroup.com/api/marketdata/page/10?endDate=" + paiva
    try:
        url = requests.get(osoite, headers = headers)
    except:
        logi("NORDPOOL ERROR 500")
        data['meta']['allowNordpoolReq'] = 0
        return hinnat
    
    vastaus = json.loads(url.text)
    logi("Nordpool api: " + osoite)
    
    for x in range(24):     
        hinta = vastaus["data"]["Rows"][x]["Columns"][5]["Value"]
        #print(tunti, " ", hinta)
        if hinnat[x] == ",":
            hinnat[x] = 0
            continue
        #Lisätään spothintaan alv ja kiinteä pohjahinta eli siirto + marginaali
        hinnat[x] = ((float(hinta.replace(",", ".")) / 10) * data['elspot_alv']) + sahkonKiinteaOsa[x]
        #hinnat[x] = (float(hinta.replace(",", ".")) / 10) <--- Tolla saa raakahinnan
        #hinnat[x] = round((hinnat[x] / 10), 4)
        hinnat[x] = float(f"{hinnat[x]:.3f}")
    logi("HAETTIIN HINNAT: " + vastaus["endDate"])
    hinnat[24] = vastaus["endDate"].strip()
    
    return hinnat


def laske_sahkon_kulutus():
    global data
    #teho = round((((1000/(data["sahko"]["pulsseja_per_kwh"] / data["sahko"]["pulssien_otanta"]))*3600)/data["sahko"]["pulssien_vali"])/1000, 3)
    
    if time.time() - data['sahko']['lastTimestamp'] < 2:
        teho = round((((1000/10000)*3600)/data['sahko']['pulssien_vali'])/1000, 3)
    else:
        teho = 0
        logi("Teho näyttää nollaa")
    #print(teho)
    minuutti = int(((datetime.datetime.today()).strftime('%-M')))
    tunti = int(((datetime.datetime.today()).strftime('%-H')))
    
    #Tarvitaan edellinen tunti, jotta saadaan kys. tunnin sähkönkulutus kohdistettua oikeaan paikkaan
    lastHourDateTime = int(((datetime.datetime.today()-datetime.timedelta(hours = 1)).strftime('%-H')))

        
    if data['currentHour'] != tunti:             # SUORITETAAN TASATUNNEITTAIN, ja vain kerran 
        data['currentHour'] = tunti
        spot_hinta_nyt = data['sahko_hinta_tanaan'][tunti] * data['elspot_alv']     #alv prosentteina
        data['kulutus_spot']                .append(round(data['piirturi_pulssit'] * ( 1 / data['sahko']['pulsseja_per_kwh']), 3))
        #Summataan kumulatiivisesti joka tunti kulutus * pörssihinta:
        data['kumul_spot_kokonaishinta'] += (data['piirturi_pulssit'] * ( 1 / data['sahko']['pulsseja_per_kwh'])) * spot_hinta_nyt  #Lisätään tämän tunnin kulutus x elspot hinta kokonaishintaan
        
        ####### VARAAJAN OHJAUKSEN MYÖTÄ TEHTYJÄ
        data['sahko']['hintaTunneittain'][lastHourDateTime]    += (data['piirturi_pulssit'] * ( 1 / data['sahko']['pulsseja_per_kwh'])) * data['sahko_hinta_tanaan'][lastHourDateTime]
        logi("Varaajan kärkitila ennen päälläoloehtoa: " + str(GPIO.input(25)))
        if tunti in data['varaajan_kayntitunnit']:
            varaajan_hallinta("varaaja_paalle")
            logi("VARAAJAN KÄYNNISTYSEHTO TÄYTTYI")
            data['vesi']['varaajan_pakotus'] = False    #Päälle laitettu pakotus poistetaan heti ensimmäisen halvan tunnin koittaessa
        elif data['vesi']['varaajan_pakotus'] == False:         # Jos pakotus ei ole päällä, voidaan sammuttaa kun tunti ei ole riittävän halpa
            varaajan_hallinta("sammuta_varaaja")
            logi("VARAAJAN SAMMUTUSEHTO TÄYTTYI")
        else:
            logi("Varaajalle ei ollut käyntituntia, mutta pakotus oli True")    #Tämän pitäisi toteutua, jos pakotus on päällä
            logi("Ei tehdä mitään ...")

        ####### ILP ######
        data['ilp']['ilp_count_per_h'].append(data['ilp']['ilp_count'])
        data['ilp']['ilp_count'] = 0
        
        
        logi("TUNTI NUMERO: " + str(tunti))
        """
       #
        #Varaajan kontaktoria ohjataan avautuvalla koskettimella, varaaja sammuu päivällä vain erikseen käskytettäessä pinout 1:lle
        #Yötariffi alkaen klo. 22:00 - päättyen 07:00
        if tunti < 7 or tunti >= 22:
            #Operaattorina OR koska tunnit on joko alle TAI yli
            logi("YÖSÄHKÖN TUNTI")
            data['vesi']['varaajan_pakotus'] = False                    #Poistaa päällepakotuksen, varaaja menee päälle muutenkin nyt, pakotus ei ole voimassa seuraavana päivänä
            GPIO.output(25, 1)                                          #Lähdön tila = 1, varaajan kontaktori sulkeutuu
            logi("Varaaja = päällä")
            data['sahko']['pulssit_yo'] += data['piirturi_pulssit']     # Summataaan Yötunnin pulssit yötariffille
            
        if (tunti >= 7 and tunti < 22):    #Päivätariffin ehto
            #Operaattorina AND koska muuten ehto toteutuisi myös klo. 22 jälkeisiltä tunneilta
            logi("PÄIVÄSÄHKÖN TUNTI")
            data['sahko']['pulssit_paiva'] += data['piirturi_pulssit']  #Summataan Päivätunnin pulssit päivätariffille
            
            if data['vesi']['varaajan_pakotus'] == False:       #Jos päällepakotus EI ole päällä
                GPIO.output(25, 0)                              #Lähdön tila = 0, varaajan sammuu
                logi("Varaaja = kiinni")
            else:                                               #Jos halutaan tehdä jotain tässäkohtaa ...
                logi("Varaaja on pakotettuna päälle päivällä! Ei tehty mitään!")
        """
        ##################
        logi("TUNTI nro. " + str(tunti) + "vaihtunut!")
        logi("Varaajan kärkitila sen jälkeen: " + str(GPIO.input(25)))
        data['piirturi_pulssit'] = 0                            #Nollataan pulssilaskuri uutta tuntia varten
        data['meta']['tuntilaskuri'] += 1
    data['sahko']['realTimeMonitorLog'].append(teho)


    ####### ILPin hetkellinen teho #############
    if data['ilp']['ilp_delay'] > 0:
        data['ilp']['ilp_teho'] = round((((1000/1000)*3600)/data['ilp']['ilp_delay'])/1000, 3)
    
def vesimittari(channel): #Keskeytyshaaskat kutsuu aina tämän paikalle, jos GPIO nastoissa tapahtuu jotain
    global data           #Keskeytyksissä summataan pulssit SEKÄ lasketaan taajuus
    if channel == 17:
        data['sahko']['pulssien_vali'] = time.time() - data['sahko']['lastTimestamp']
        data['sahko']['kulutusTunneittain'][data['currentHour']] += 1
        data['piirturi_pulssit'] += 1
        data['sahko']['lastTimestamp'] = time.time()
        return 0
    if channel == 26: 
        data['vesi']['taajuus'] = 1 / (time.time() - data['vesi']['lastTimestamp'])
        data['vesi']['lastTimestamp'] = time.time()
        data['vesi']['ulkokierto_count'] += 1
        return 0
    if channel == 13:
        data['vesi']['kylma_vesi_taajuus'] = 1 / (time.time() - data['vesi']['kylma_vesi_lastTimestamp'])
        data['vesi']['kylma_vesi_lastTimestamp'] = time.time()
        data['vesi']['kylma_vesi_count'] += 1
        return 0
    if channel == 6:
        data['ilp']['ilp_delay'] = time.time() - data['ilp']['lastTimestamp']
        data['ilp']['ilp_count'] += 1
        data['ilp']['lastTimestamp'] = time.time()
        

def pysayta_mittari(): #Kun virtaus pysähtyy, ei keskeytystä enään tule == ei jätetä edellistä taajuuslukemaa päälle
    global data
    if time.time() - data['vesi']['lastTimestamp'] > 1:
        data['vesi']['taajuus'] = 0
    if time.time() - data['vesi']['kylma_vesi_lastTimestamp'] > 1:
        data['vesi']['kylma_vesi_taajuus'] = 0
    if time.time() - data['ilp']['lastTimestamp'] > 360:
        data['ilp']['lastTimestamp'] = time.time()
        logi("Nollattiin ILPin mittari")
        data['ilp']['ilp_teho'] = 0
    
    #if time.time() - data['sahko']['lastTimestamp'] > 1:
    #    data['sahko']['pulssien_vali'] = False
        
        
def mittaa_lampotila():
    global f
    val_2 = ADS.readADC(0)
    val_1 = ADS.readADC(2)

    jannite = val_2 * f
    vastus = round(47000 / ((val_1 * f) / jannite -1), 2)
    #print("Analog2: {0:d}\t{1:.3f} V".format(val_2, jannite))
    #B VALUE = 3950
    lampo = (1 / (1 / 298.16 +1 / 3950 * ln(vastus / 50000))) - 273.15

    #print(lampo , "vastus: " , vastus, "3.3 jannite: ", val_1 * f)
    return lampo

    
def logi(txt):
    print("[", datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), " ] ", txt)
    data['lastLogs'].append("[" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "] "  + txt + "")
    time.sleep(1)


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    logi("Threaded Mixin luokkaa kutsutaan!")
    """Handle requests in a separate thread."""

def create_server():
    port = 3323
    global data, vesi
    httpd = ThreadedHTTPServer(("0.0.0.0", port), handler)
    logi("HTTP KUUNTELEE PORTISSA " + str(port))
    httpd.serve_forever()

try: #Jos data array on aiemmin dumpattu tiedostoon talteen
    with open("demofile3.txt", "r") as file:
        logi("TIEDOSTO LÖYTYI")
        data = json.loads(file.read())
        file.close()
except:
    logi("Ei tiedostoa")


#ADS = ADS1x15.ADS1115(1, 0x48)
#ADS.setGain(ADS.PGA_4_096V)
#f = ADS.toVoltage()
#ADS.setDataRate(0)


#Haaskat odottamassa:
benchmark = False

if benchmark == False:
    GPIO.setmode(GPIO.BCM)
    
    GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)     #Kuuma vesi
    GPIO.add_event_detect(26, GPIO.FALLING, bouncetime=2)
    GPIO.add_event_callback(26, vesimittari)

    GPIO.setup(13, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)     #Kylmä vesi
    GPIO.add_event_detect(13, GPIO.FALLING, bouncetime=2)
    GPIO.add_event_callback(13, vesimittari)


    GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)     #Sähkömittari
    GPIO.add_event_detect(17, GPIO.FALLING, bouncetime=2)
    GPIO.add_event_callback(17, vesimittari)
    
    GPIO.setup(6, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)     # ILP sähkömittari
    GPIO.add_event_detect(6, GPIO.FALLING, bouncetime=30)
    GPIO.add_event_callback(6, vesimittari)

    #GPIO.setup(21, GPIO.OUT, initial=GPIO.LOW)
    #GPIO.setup(20, GPIO.OUT, initial=GPIO.LOW)
    GPIO.setup(25, GPIO.OUT, initial=GPIO.HIGH)
    #Varaajan kärki. Avautuva kosketin = oletuksena varaajan kontaktorille avautuva kosketin, varaaja silloin päällä





for i in range(5):
    time.sleep(1)
    logi("odotetaan " + str(i))

#Kodin hengetär tekee ns. raskaat, aikaa vievät työt ja paskahommat
#Sekunttikierto laskee veden kulutukset ja sen keston täytyy olla tarkasti sekuntti


time.sleep(1)

_thread.start_new_thread(kodin_hengetar, tuple())
logi("Kodin hengerät käynnistetty!")
hearthbeat()
logi("hearthbeat() käynnistetty!")

time.sleep(1)


_thread.start_new_thread(create_server, tuple())

data['meta']['restartTimes'] += 1
kaynnistysaika = math.ceil(time.time())

try:
    start = time.time()
    while True:             #Mainloop ei tee muuta kuin odottaa pysäytyskäskyä näppikseltä
        #print(data["vesi"]["ulkokierto_count"])
        #print(data["sahko"]["pulssien_vali"])
        #time.sleep(1 / 183.333)
        #vesimittari(26)
        #print(time.time() - start)
        time.sleep(2)
except KeyboardInterrupt:
    #logi("tallennetaan data")
    #file = open("demofile3.txt", "w")
    #file.write(json.dumps(data))
    #file.close()
    data['meta']['ajoaikaSec'] += (math.ceil(time.time()) - kaynnistysaika)
    
    print("\nTidying up")

SELAINPUOLI

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
aside {
  width: 25%;
  padding-left: 15px;
  margin-left: 15px;
  float: right;
  background-color: lightgray;
}
section {
    margin: 10px;
    padding: 10px;
}

</style>
<body>

    <div id="kulutus"></div>
    
     <nav style="font-size:1.5vw; background-color: Aquamarine; padding: 5px;" id="tiedot"></nav>

     <section style="font-size:1.5vw;background-color: rgba(255, 255, 255, 0.1); float: right; " id="kulutusajakauma"></section>
     <section style="font-size:1.5vw;background-color: rgba(255, 255, 255, 0.4);" id="ilp"></section>
     <section style="font-size:1.5vw;background-color: rgba(255, 255, 255, 0.4);" id="tuntitieto"></section>




    <!--<svg id="kulutus_bars" width='400' height='100' style="border: 1px solid black;" ></svg>-->

   <aside style="font-size:1.5vw;">
        <h4>Veden kulutus tänään</h4>
        <p style=" border: 1px dotted blue; padding: 5px; margin: 5px;">
            <span style="color: blue;" id="kylmavesi"></span><br />
            <span style="color: red;" id="kuumavesi"></span><br />
            <span style="color: green;" id="lammitysteho"></span><br />
            <span id="veden_arvo"></span>
            <span id="ulkokierron_lammot"></span>
            </p>
            <h4>Veden kulutus päivittäin</h4>
            <span id="vesi_paivittain"></span>
            <p>

            <!--<span style="color: green;" id="saasto"></span><br />
            <span id="paluulampo"></span><br /><br />--->
            <button onclick="pakota_varaaja_paalle()">Pakota varaaja päälle</button><br />
            <span><canvas id="varaajan_tila" width="200" height="30" style="border:1px solid balck; margin: 10px;"></span>
            <span id="varaajan_lataus"></span>
            <!-- <span style="color: magenta; text-decoration: underline;">Kuuman veden arvo:</span> -->

        </p>
        <p style="border: 1px solid black; margin: 5px; padding: 5px;">
            <span style="text-decoration: underline;">Ajonaikaisia tietoja</span><br /><br />
            <span>JavaConsole:<br /></span>
            <textarea rows="1" cols="1" id="javaLog" style="width: 200px; height: 50px;"></textarea><br />
            <span id="saikeita"></span><br />
            <span id="lahetetty"></span><br />
            <span id="pulsseja"></span><br />
            <span id="nordpool"></span><br />
            <span id="nordpoolaccess"></span>
            <span id="pvm"></span><br />
            <span id="paikalla"></span><br />
            <span id="pyyntoja"></span><br />
            <span id="restartTimes"></span><br />
            <span id="ajoaika"></span><br />
            <a href="./debug">DEBUG</a><br />
            
            
        </p>

    </aside>
    <!---<div id="myPlot" style="width:60%; margin-top: 10%px; height: 400px; border: 1px solid black;"></div>
    
    <!---<h1>ILP kulutus</h1>
    <div id="ILP" style="width:100%;max-width:600px; height: 400px; border: 1px solid black;"></div>
    <!--<h1>Veden kulutus</h1>
    <div id="vesi" style="width:100%;max-width:600px; height: 400px; border: 1px solid black;"></div>--->
    <button onclick="nayta_ilp_naytto()">Näytä ILP sähkö</button>
    <button onclick="nayta_sahkonhinta()">Näytä sähkön hinta</button>
    <button onclick="nayta_vedenkulutus()">Näytä veden kulutus</button>
    <button onclick="nayta_kulutusjakauma()">Näytä kulutusjakauma</button>
    <button onclick="varaajan_suunnitelma()">Varaajan suunnitelma</button>
    
    <div style="width: 600px; border: 1px solid black;margin: 5px;"><canvas id="myChart"></canvas></div>
    <button onclick="nayta_kaikkilammot()">Kaikki lämmöt</button>
    <button onclick="nayta_lammot_tunti()">Viimeisin tunti</button>
    <div style="width: 600px; border: 1px solid black; margin: 5px;"><canvas id="lammot"></canvas></div>


<h3 style="">Logi</h3>
    <textarea rows="10" cols="10" id="lastlog" style="width: 60%; height: 100px;"></textarea>



<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>





</body>
</html>

<script>


/*window.addEventListener('load', () => {
  document.body.style.backgroundColor = 'yellow';
});*/

var ylempiGraafi = "sahkon_hinta";
var lampoGraafi = "viimeisin_tunti";
function pakota_varaaja_paalle() {
    fetch("/pakota_varaaja_paalle");
}
function nayta_ilp_naytto() {
    ylempiGraafi = "ilp_kulutus";
    hae_kaikki_data();
    //fetch("/etusivu.html");
}
function nayta_sahkonhinta() {
    ylempiGraafi = "sahkon_hinta";
    hae_kaikki_data();
    
    //fetch("/etusivu.html");
}
function nayta_vedenkulutus() {
    ylempiGraafi = "veden_kulutus";
    hae_kaikki_data();
}
function nayta_kulutusjakauma() {
    ylempiGraafi = "kulutusjakauma";
    hae_kaikki_data();
}
function varaajan_suunnitelma() {
    ylempiGraafi = "varaajan_suunnitelma";
    hae_kaikki_data();
}
function nayta_kaikkilammot() {
    lampoGraafi    = "kaikki";
    hae_kaikki_data();
}
function nayta_lammot_tunti() {
    lampoGraafi = "viimeisin_tunti";
    hae_kaikki_data();
}
function varaaja_canvas(lataus) {
   // console.log("Varaajan lataus:" + lataus);
    var c = document.getElementById("varaajan_tila");
    var ctx = c.getContext("2d");
    var grd = ctx.createLinearGradient(0, 0, 200, 0);
    
    grd.addColorStop(0, "blue");
    grd.addColorStop(1, "red");

    // Fill with gradient
    ctx.fillStyle = grd;
    ctx.fillRect(0, 0, 200 * lataus, 20);
}
function viivasto_y (tiheys, max_y, max_x, style = "stroke:black;stroke-width:1 px") {
	let output = "", i, y_pointer = 0 / tiheys, x_offset = 0, x = 0 ;
	for (i = 0; i < tiheys; i++) {
		output += `<line x1="${x_offset}" y1="${y_pointer + (max_y / tiheys)}" x2="${max_x}" y2="${y_pointer + (max_y / tiheys)}" style="${style}" />` + "\n";
		y_pointer += max_y / tiheys;
	}
	
	//console.log(output);
	return output;
}
function viivasto_y (tiheys, max_x, max_y, style = "stroke:black;stroke-width:1 px") {
	let output = "", i, y_pointer = 0 / tiheys, x_offset = 0, x = 0 ;
	for (i = 0; i < tiheys; i++) {
		output += `<line x1="${x_offset}" y1="${y_pointer + (max_y / tiheys)}" x2="${max_x}" y2="${y_pointer + (max_y / tiheys)}" style="${style}" />` + "\n";
		y_pointer += max_y / tiheys;
	}
	
	//console.log(output);
	return output;
}
function arvo_luvut(montako) {
	const a = [];
	for (let i = 0; i < montako; i++) {
		 a[i] = Math.floor(Math.random() * 100);
		 //console.log(Math.floor(Math.random() * 100));
	}
	console.log(a);
	return a;
}
function generate_points(values, max_y = 600, max_x = 600) {
	//let values = [20,20,50,30,30,20];
	let minmax = get_minMax(values);
	let output = "", i, x_step = Math.trunc(max_x / values.length), y_step = max_y / minmax[1], x_pointer = 0, y_ax = 0;
	//console.log("x-step values : " + values + max_y, max_x);
	//console.log("pituus: " + values.length);
	//console.log(get_minMax(values));
	
	for (i = 0; i < values.length; i++) {
		//console.log(values[i]);
		y_ax = max_y - Math.trunc(values[i] * y_step);
		output += x_pointer + "," + y_ax + " ";
		x_pointer += x_step;
		//console.log("x-step : " + x_step);
		//console.log("x-pointer : " + x_pointer);
		//console.log("y-ax : " + y_ax);
		//console.log("output : " + output);
	}
	output = output.substr(0, output.length);
	//console.log("generate points : " + output);
	return output;
}
function sum_element(a) {
    let s = 0;
    for (i = 0; i < a.length; i++) {
        s += a[i];
    }
    return s;
}
function generate_bars (values, x_max, y_max, style = `style="fill:green;fill-opacity:0.4;stroke:green;stroke-width:1"`, x_margin, y_margin) {
	let output = "", i, x_pointer = x_margin, x_step = 0, y_fact, vaihtelu = 0;
	let minmax = get_minMax(values);

	x_step = (x_max / values.length) - 3 ;

	y_fact = (  (y_max - y_margin)  / minmax[1]);
    y_line = ( y_max * 0.4) ;
    
    output += `<line x1="0" y1="${y_line}" x2="${x_max}" y2="${y_line}" style="stroke:black" />\n`;
	for (i = 1; i < values.length; i++) {
		output += `<rect width="${x_step }" height="${ ((values[i])  * (y_fact))}" x="${x_pointer}", y="${y_max - (values[i]  * y_fact)}" ${style} />` + "\n";
		x_pointer = x_pointer + x_step + 3;
	}

	return output;
}
function precise(x, m = 3) {
  return x.toPrecision(m);
}
function get_minMax(arr) {
	const min = Math.min(...arr);
	const max = Math.max(...arr);
	const index_min = arr.indexOf(min);
	const index_max = arr.indexOf(max);
	return [arr[index_min], arr[index_max], (arr[index_max] - arr[index_min]) ];
}
function ulosta(id, txt) {
    document.getElementById(id).innerHTML = txt;
}
function ulostaJava(asia) {
    javaLog.unshift(asia);
    console.log(asia);
}

let sahkovero = 0.0279372;
let energiahinta = 0.221;



var source = new EventSource("/nayttopaate66/livestream");
const realTimeMonitorLog = [];
const lastlogLammot = {'imu': [], 'puhallus': [], 'ottoteho': [], 'ottoteho_avg': [], 'lammitysteho' : []};
const lastLog = [];
const hinnat = {'paiva' : {'energia' : 0.2210, 'siirto' : 0.0408}, 'yo' : {'energia' : 0.1490, 'siirto' : 0.0267}, 'sahkovero' : 0.0279372, 'yksAikaHinta' : 0.1990};
const d = new Date();
const javaLog = [];
var laskuri = 0;
var kokonaishinta_paiva = hinnat['paiva']['siirto'] + hinnat['paiva']['energia'] + hinnat['sahkovero'];
var kokonaishinta_yo = hinnat['yo']['siirto'] + hinnat['yo']['energia'] + hinnat['sahkovero']; 
var kokonaishinta_yksAika = hinnat['paiva']['siirto'] + hinnat['yksAikaHinta'] + hinnat['sahkovero'];
var energian_hinta_nyt, paivaVaiYo, paivaVaiYo_color;


source.onmessage = function(event) {
	const obj = JSON.parse(event.data);
    //console.log(obj['lastLogs']);
	let output;
	realTimeMonitorLog.push((obj['realTimeMonitorLog']));
    lastlogLammot['imu'].push(obj['parvi']);
    lastlogLammot['puhallus'].push(obj['sisa_puhallus']);
    lastlogLammot['ottoteho'].push(obj['ilp_teho'] * 1000);
    //lastlogLammot['lammitysteho'].push((((obj['sisa_puhallus'] - obj['parvi']) * 800 * 1.25) / 3600).toFixed(2));
    
    
    ulosta('tuntitieto', "Sähkön hinta nyt: " + obj['sahkon_hinta_nyt'].toFixed(2) + " c Meneillään oleva tunti: " + obj['kuluva_tunti']);
    
    laskuri++;
    //ulostaJava(laskuri);
    if (laskuri == 60) {
        lastlogLammot['ottoteho_avg'].push(lastlogLammot['ottoteho'].reduce((a,c) => a + c, 0) / lastlogLammot['ottoteho'].length);
        
        laskuri = 0;
    }
let COP = ((((obj['sisa_puhallus'] - obj['parvi']) * 800 * 1.25) / 3600).toFixed(2) / ((lastlogLammot['ottoteho'].reduce((a,c) => a + c, 0) / lastlogLammot['ottoteho'].length) / 1000)).toFixed(2);
    //console.log(lastlogLammot);
    
    if (d.getHours() < 7 || d.getHours() >= 22) {
        energian_hinta_nyt = kokonaishinta_yo;
        paivaVaiYo = "yötunnilta";
        paivaVaiYo_color = 'blue';
    }
    if (d.getHours() >= 7 && d.getHours() < 22) {
        energian_hinta_nyt = kokonaishinta_paiva;
        paivaVaiYo = "päivätunnilta";
        paivaVaiYo_color = 'OrangeRed';
    }

    //const numbers = [3,4,5,2,4,6,78,53,2,1,2];
    //const sum = numbers.reduce((a,c) => a + c, 0);
    //const avg = sum / numbers.length;

    
	if (lastlogLammot['imu'].length > 300) {
		lastlogLammot['imu'].shift();
	}
	if (lastlogLammot['puhallus'].length > 300) {
		lastlogLammot['puhallus'].shift();
	}
	if (lastlogLammot['ottoteho'].length > 60) {
		lastlogLammot['ottoteho'].shift();
	}
	if (lastlogLammot['ottoteho_avg'].length > 10) {
		lastlogLammot['ottoteho_avg'].shift();
	}
	if (lastlogLammot['lammitysteho'].length > 60) {
		lastlogLammot['lammitysteho'].shift();
	}
	if (realTimeMonitorLog.length > 100) {
		realTimeMonitorLog.shift();
	}
    if (obj['lastLogs'] != 0) {
        lastLog.unshift(obj['lastLogs']);
    }
    if (lastLog.length > 7000) {
        lastLog.pop();
    }
    const p = new Date();
    ulostaJava(((p.getMinutes() + p.getSeconds() / 60) / 60))
    let kuluvaTunti = d.getHours();
    let teho_keskimaarin = ((obj['pulsseja_laskettu'] * 0.0001) / (obj['meta']['tuntilaskuri'] + (p.getMinutes() / 60))).toFixed(3); // huomioidaan kuluvan tunnin minuutit mukaan keskiarvon pituuteen
    //teho_keskimaarin = teho_keskimaarin * 2;
    let vari, r = 0, g = 0, b = 0, t = 0.5;
    if (obj['realTimeMonitorLog'] < teho_keskimaarin) {
        t = precise(1 - (obj['realTimeMonitorLog'] / teho_keskimaarin), 2);
        g = 255;
    }
    if (obj['realTimeMonitorLog'] >= teho_keskimaarin) {
        t = precise(1 - (teho_keskimaarin / obj['realTimeMonitorLog']), 2);
        r = 255;
    }
    
    if (t > 1) { t = 1; }
    if (t <= 0) { t = 0.02; }
    vari = `rgba(${r}, ${g}, ${b}, ${t})`;
    console.log(obj['sahkon_hinta_nyt']);
    ulosta("kulutus", "<header style='font-size:5vw; text-align: center; background-color: " + vari + ";'>" + obj['realTimeMonitorLog'].toFixed(2) + " kW, " + "" + (obj['realTimeMonitorLog'] * (obj['sahkon_hinta_nyt']) / 100).toFixed(2) + "" + " eur/h, == " + ((obj['realTimeMonitorLog'] * (obj['sahkon_hinta_nyt']) / 100) * 24).toFixed(2) + " eur/päivä </header>");
    ulosta("tiedot", "" + "Kumulatiivinen: <b>" + (obj['pulsseja_laskettu'] * 0.0001).toFixed(3) + "</b> kWh, <s>euroja kulunut " + (obj['pulsseja_laskettu'] * 0.0001 * energiahinta).toFixed(2) + " euroa.</s> (Energian osuus: <b>" + (obj['kumul_spot_kokonaishinta'] / 100).toFixed(2) + "</b> eur spot, Yleissähkömittauksella: <b>" + ((obj['pulsseja_laskettu'] * 0.0001) * hinnat['yksAikaHinta']).toFixed(2) + "</b> EUR)<br />" + "Liittymäteho keskimäärin: " + teho_keskimaarin + " kW");


    ulosta('kulutusajakauma', "<s><span style='color: OrangeRed;'>Päivätunnit: <b>" + (obj['pulssit_paiva'] / 10000).toFixed(1) + "</b> kWh, <b>" + ((obj['pulssit_paiva'] / 10000) * kokonaishinta_paiva).toFixed(2) + "</b> EUR</span>, <span style='color: blue;'>Yötunnit: <b>" + (obj['pulssit_yo'] / 10000).toFixed(1) + "</b> kWh, <b>" + ((obj['pulssit_yo'] / 10000) * kokonaishinta_yo).toFixed(2) + "</b> EUR, </span><span style='color: magenta;'>== <b>" + ((obj['pulssit_paiva'] / 10000) + (obj['pulssit_yo'] / 10000)).toFixed(1) + "</b> kWh (<b>" + (((obj['pulssit_paiva'] / 10000) * kokonaishinta_paiva) + ((obj['pulssit_yo'] / 10000) * kokonaishinta_yo)).toFixed(2) + "</b> EUR </span>" +
            ",<br /><span style='color: " + paivaVaiYo_color + "'>Kuluvalta " + paivaVaiYo + ": <b>" + (obj['piirturi_pulssit'] / 10000).toFixed(4) + "</b> kWh, <b>" + ((obj['piirturi_pulssit'] / 10000) * energian_hinta_nyt).toFixed(2) + "</b> EUR</span>, Kokonaishinta 1-aikamittauksella: <b>" + ((obj['pulsseja_laskettu'] / 10000) * (kokonaishinta_yksAika)).toFixed(2) + "</b> EUR</s>");
    
    // Puhallusteho m3/h 800/720/570/620/560/500/450
    let antoteho = ((((obj['sisa_puhallus'] - obj['parvi']) * 800 * 1.25) / 3600).toFixed(2));
    if (antoteho < 0) {
        antoteho = "<span style='color: blue;'>Jäähdytysteho: <b>" + (antoteho * -1) + "</b> kW</span>";
    } else {
        antoteho = "<span style='color: red;'>Lämmitysteho: <b>" + antoteho + "</b> kW</span>";
    }
    ulosta('ilp', "ILP kokonaiskulutus: <b>" + (obj['ilp_count'] / 1000).toFixed(3) + "</b> kWh<br /> " + "Ottoteho: <b>" + (obj['ilp_teho'] * 1000).toFixed(1) + "</b>" + " W / <b>" + (lastlogLammot['ottoteho'].reduce((a,c) => a + c, 0) / lastlogLammot['ottoteho'].length).toFixed(1) +"</b> W/avg, <br />" + antoteho + ",<br /> COP: " + COP + " ,<br />Ottoteho / 10min:" + lastlogLammot['ottoteho_avg'].reduce((a,c) => a + c, 0) / lastlogLammot['ottoteho_avg'].length.toFixed(2) + "<br />Ulkolämpö: <b>" + obj['ulkolampo'].toFixed(2) + "</b> c, sisälämpö: <b>" + obj['sisalampo'].toFixed(2) + "</b> c, lämpö parvella: <b>" + obj['parvi'].toFixed(2) + "</b> c ; Puhalluslämpö: <b>" + obj['sisa_puhallus'].toFixed(2) + "</b> c <br />" + "");
    
    
    // Vesimittarien kertoimet 1/2 = 11 ja 3/4 = 6.6

    
    document.getElementById("saikeita").innerHTML = "Säikeitä käynnissä: " + obj['meta']['saikeitaKaynnissa'];
    //document.getElementById("lahetetty").innerHTML = "Dataa lähetetty: " + obj['meta']['broadcastedBytes'];
    ulosta("lahetetty", "Dataa lähetetty: " + ((obj['meta']['broadcastedBytes'] / 1024 / 1024).toFixed(3)) + " MB");
    document.getElementById("pvm").innerHTML = "Päivämäärä: " + obj['meta']['paivamaaraTanaan'];
    document.getElementById("nordpool").innerHTML = "NordPooliin pyynnöt: " + obj['meta']['nordpoolReqTimes'];
    document.getElementById("pulsseja").innerHTML = "Pulsseja laskettu: " + obj['pulsseja_laskettu'];
    document.getElementById("lastlog").innerHTML = "" + lastLog.join("\n");
    document.getElementById("paikalla").innerHTML = "Asiakkaita paikalla: " + obj['meta']['asiakkaitaPaikalla'];
    document.getElementById("pyyntoja").innerHTML = "HTTP pyyntöjä saatu: " + obj['meta']['httpPyyntojaSaatu'];
    document.getElementById("restartTimes").innerHTML = "Datadumppi käynnistetty: " + obj['meta']['restartTimes'] + " kertaa";
    ulosta("ajoaika", "Uptime käynnistyksestä: <b>" + (obj['meta']['tuntilaskuri'] - obj['meta']['ajoaikaSec'] / 3600) + "</b> h <br /> Ajettu kaikkiaan: <b>" + obj['meta']['tuntilaskuri'] + "</b> h <br /> Datadumppi luotu: " + obj['meta']['datadumppiLuotu'] + "");
    
    document.getElementById("kylmavesi").innerHTML = "Kylmä vesi: <b>" + precise(obj['vesi']['kylma_vesi_count'] / 6.6 / 60, 5) + "</b> l (<b>" + precise(obj['vesi']['kylma_vesi_taajuus']/6.6) + "</b> l/min)";
    let kuumanVirtausnopeus = precise(obj['vesi']['taajuus'] / 11);

    document.getElementById("kuumavesi").innerHTML = "Kuuma vesi: <b>" + precise(obj['vesi']['ulkokierto_count'] / 11 / 60, 5) + "</b> l (<b>" + kuumanVirtausnopeus + "</b> l/min, <b>" + precise(((obj['vesi']['taajuus'] / 11) / 60) * (80 * 4.2)) + "</b> kW )"; //Hetkellinen teho lämpötilaerolla 80 astetta, X virtauksella
    document.getElementById("lammitysteho").innerHTML = "Ulkokierron lämmitysteho:: <b style='color: red;'>" + precise(((obj['vesi']['taajuus'] / 11) / 60) * ((obj['vesi_ulkokierto_tmp'] - obj['vesi_ulkokierto_meno']) * 4.2)) + "</b> kW";
    ulosta("ulkokierron_lammot", "Pöntön lämpötila: <b>" + obj['vesi_ponton_tmp'] + "</b> c, <br /> Kylmän veden menolämpö: <b>" + obj['vesi_ulkokierto_meno'] + "</b> c <br />Ulkokierron paluulämpö: <b>" + obj['vesi_ulkokierto_tmp'] + "</b> c");
    
    //document.getElementById("saasto").innerHTML = "Ulkokierron säästö: " + precise(obj['vesi']['kierron_saasto'], 4) + " kWh (" + precise(obj['vesi']['kierron_saasto'] * (0.0279372 + 0.0408 + 0.089), 2) + " eur)";
    //document.getElementById("paluulampo").innerHTML = "Ulkokierron paluulämpö " + precise(obj['vesi']['kierron_paluulampo']) + " c";
    //document.getElementById("kuuman_veden_laskelma").innerHTML = "" + ((((obj['vesi']['ulkokierto_count'] / 11 / 60) * 80 * 4.2)  * (0.0279372 + 0.0408 + energiahinta)) / 3600).toFixed(2) + " EUR, " + ((obj['vesi']['ulkokierto_count'] / 11 / 60) * 80 * 4.2).toFixed(2) + " kWh";
    document.getElementById("varaajan_lataus").innerHTML = "Varaajan latausaste: " + precise(obj['vesi']['varaajan_status'] / obj['vesi']['varaajan_kapasiteetti'] * 100, 4) + " %" + "<br />Veden riittävyys: <span style='font-size: 12px;'>Ohjauskärjen tila: <b>" + obj['varaajan_karkitieto'] + "</b> (0 = kiinni, 1 = päällä)<br />Pakotuksen tila: <b>" + obj['vesi']['varaajan_pakotus'] + "</b></span>";
    //let kylman_veden_maara = obj['vesi']['kylma_vesi_count'] / 6.6 / 60;
    //document.getElementById("veden_arvo").innerHTML = "<br /> <b>" + precise(kylman_veden_maara / 1000 * 2.58) + "</b> EUR (<b>" + precise(kylman_veden_maara / 1000 * (2.58 + 3.19)) + "</b> EUR jätevesineen)<br />Porakaivosta kuoletettu <b>" + precise(kylman_veden_maara / 1000 * (2.58 / 4860 * 100)) + "</b> % <br /> <b>" + precise((4860 / 2.58) - (kylman_veden_maara / 1000), 7) + "</b> kuutiota kuoletukseen "  ;

    ulosta("javaLog", javaLog.join("\n"));
}

var kk; //vedenkulutusnäyttö
var lampoGraafi;
var kk_lampo;

function sahkon_hinta(txt) {

	var hinta_tanaan = ((txt['sahko_hinta_tanaan'].map(Number)).slice(0, -1));
    var hinta_huomenna = (txt['sahko_hinta_huomenna'].map(Number)).slice(0, -1);
    
    console.log(hinta_tanaan);

    
    var kylma_paivittain = (txt['vesi_logi']['kylma_paivittain']);
    var lammin_paivittain = (txt['vesi_logi']['lammin_paivittain']);
    //console.log(lammin_paivittain);
    let output = "";
    let kuuma_vesi_yhteensa = txt['vesi_logi']['lammin_paivittain'].reduce((x, y)=> x+y);   //summaa taulukon
    output += "<span style='color: blue;'>Kylmä vesi yhteensä: " + ((txt['vesi_logi']['kylma_paivittain'].reduce((x, y)=> x+y))/1000).toFixed(2) + " m3 </span><br />";
    output += "<span style='color: red;'>Kuuma vesi yhteensä: " + (kuuma_vesi_yhteensa / 1000).toFixed(2) + " m3,<br />Veden arvo: " + ((80*kuuma_vesi_yhteensa*4.2)/3600) * (kokonaishinta_yo) + " </span><br />";

    /*for (i = 0; i < kylma_paivittain.length; i++) {
        
        output += "<span style='color: blue;'>" + (kylma_paivittain[i]).toFixed(1) + "</span> \n";
        output += "<span style='color: red;'>" + (lammin_paivittain[i]).toFixed(1) + "</span><br />\n";
        output += "<hr />\n";
    }*/


    //console.log(output);
    document.getElementById("vesi_paivittain").innerHTML = output;
    

    //console.log(hinta_huomenna);
    
    
    
    
    const xArray = [];
    xArray.fill("0", 0, 24);
    //if (hinta_huomenna[0] != 0) {
    //    hinta_tanaan = hinta_tanaan.concat(hinta_huomenna);
   //     xArray.concat(xArray);
   // }
    

    //console.log(hinta_tanaan);
    var data = [{
      x:xArray,
      y:hinta_tanaan.map(n => (n * 1.09091).toFixed(3)),
      type:"bar",
      name: "Hinta tänään"
    }];

    let kiintea_hinta = Array(24);
    kiintea_hinta.fill(14.9, 0, 7);
    kiintea_hinta.fill(22.1, 7, 22);
    kiintea_hinta.fill(14.9, 22, 24);

    let timestamp = (txt['sahko']['aloitusaika'] * 1000);

   
    var luku = (d - timestamp) / 3600000 | 0;
    //console.log(luku);
    data.push({x0: ((0 - txt['kulutus_spot'].length) + (d.getHours() + 1)), dx: 1, y: txt['kulutus_spot'], type: "line", yaxis: {range: [0,4]}, name:"Kulutus / kWh"});
        data.push({x0: ((0 - txt['kulutus_spot'].length) + (d.getHours() + 1)), dx: 1, y: txt['kulutus_spot'].map(x => x * 21), type: "bar", yaxis: {range: [0,4]}, name:"Hinta / snt"});

        //Plotly.newPlot("myPlot", data, layout, {displayModeBar: false, responsive: true});
    
    //console.log(txt['vesi']['varaajan_status']);
    varaaja_canvas(txt['vesi']['varaajan_status'] / txt['vesi']['varaajan_kapasiteetti']);

    const dataset=[];
    const ctx = document.getElementById('myChart');
    
    if (ylempiGraafi == "varaajan_suunnitelma") {
        //dataset.push({label: 'Hinta tänään', data: hinta_tanaan.map(n => (n * 1.09091).toFixed(3)), borderWidth: 1, backgroundColor: "#33AEEF"});
        suunnitelmat = Array(24+24).fill(0);
        let lammitysteho = txt['vesi']['varaajan_lammitysteho'];
        for (i = 0; i < txt['varaajan_kayntitunnit'].length; i++) {
            suunnitelmat[txt['varaajan_kayntitunnit'][i]] = lammitysteho;
            //console.log("varaajna käyntitunnit: " + txt['varaajan_kayntitunnit'][i]);
        }
        console.log(suunnitelmat);
        tarve = Array(24+24);
        tarve.fill(txt['sahko']['varaajan_tarve'] );
        let kohtaanto;
        for (i = 0; i < tarve.length; i++) {
            //tarve[i] -= suunnitelmat[i];
            kohtaanto = tarve[i] - suunnitelmat[i];
            if (kohtaanto < 0) {
                kohtaanto = 0;
            }
            tarve.fill(kohtaanto, i, tarve.length);
            
           // console.log(tarve[i] + " " + suunnitelmat[i]);
        }
      if (hinta_huomenna[0] != 0) {
        hinta_tanaan.push.apply(hinta_tanaan, hinta_huomenna);

      }
       //let aloitus = d.getHours();
        let aloitus = 0;
        console.log(tarve);
        dataset.push({label: 'Energian suhteellinen hinta', data: hinta_tanaan.map(i => i ).slice(aloitus), borderWidth: 2, pointRadius: 2, fill: false, backgroundColor: "green", borderWidth: 1, borderColor: "green", type: "line"});
        dataset.push({label: 'Lämmitystarve / kWh', data: tarve.slice(aloitus), pointRadius: 0, type: 'line', fill: true, borderColor: 'purple', borderWidth: 0, backgroundColor: "rgba(255,10,13,0.1)"});
        dataset.push({label: 'Suunniteltu lämmitysajankohta', data: suunnitelmat.slice(aloitus), pointRadius: 0, type: 'bar', fill: false, borderColor: 'purple', borderWidth: 1, backgroundColor: "red"});

    if (kk) {
        kk.destroy();
        ulostaJava("TUHOTTIIN VANHA paikassa varaajan suunnitelma");
    }
    let label;
    label = Array.from({length: 24}, (v, k) => k++ + ":00").slice(aloitus).concat(Array.from({length: 24}, (v, k) => k++ + ":00"));
    ulostaJava(label);
    kk = new Chart(ctx, {
        
        type: 'bar',
        data: {
          //labels: Utils.months({count: 24}),
          labels: label,
          datasets: dataset
        },
        options: {
            title: {
                    display: true,
                    text: 'Kellon aika',
                    position: 'bottom'

            },
            scales: {
                y: {
                    suggestedMin: 0,
                    suggestedMax: 25
                    //stacked: 'single'
                }
            },
            animation: false
        }
      });
    }
    
    if (ylempiGraafi == "sahkon_hinta") {
        //dataset.push({label: 'Hinta tänään', data: hinta_tanaan.map(n => (n * 1.09091).toFixed(3)), borderWidth: 1, backgroundColor: "#33AEEF"});
        dataset.push({label: 'Hinta tänään', data: hinta_tanaan, borderWidth: 1, backgroundColor: "#33AEEF"});

      if (hinta_huomenna[0] != 0) {
        //dataset.push({label: 'Hinta huomenna', data: hinta_huomenna.map(n => (n * 1.09091).toFixed(3)), borderWidth: 1, backgroundColor: "green"});
        dataset.push({label: 'Hinta huomenna', data: hinta_huomenna, borderWidth: 1, backgroundColor: "green"});
      }
      dataset.push({label: 'Kiinteä hinta', data: kiintea_hinta, pointRadius: 0, type: 'line', fill: false, borderColor: 'red', borderWidth: 1, backgroundColor: "#33AEEF"});

      
    if (kk) {
        kk.destroy();
        ulostaJava("TUHOTTIIN VANHA paikassa sähköninta");
    } 
    kk = new Chart(ctx, {

        type: 'bar',
        data: {
          //labels: Utils.months({count: 24}),
          labels: Array.from({length: 24}, (v, k) => k++ + ":00"),
          datasets: dataset
        },
        options: {
            title: {
                    display: true,
                    text: 'Kellon aika',
                    position: 'bottom'

            },
            animation: false
        }
      });
      console.log(kk);
     }
     let osoitin = Array(24);
     osoitin[10] = 100;
    if (ylempiGraafi == "kulutusjakauma") {
    
        dataset.push({label: 'Kulutus kWh', data: txt['sahko']['kulutusTunneittain'].map(i => (i / 10000).toFixed(3)), borderWidth: 1, backgroundColor: "#33AEEF"});
        dataset.push({label: 'Hinta tunneittain', data: txt['sahko']['hintaTunneittain'].map(i => (i / 100).toFixed(2)), borderWidth: 1, backgroundColor: "red"});
        if (txt['meta']['tuntilaskuri'] > 24) {
            dataset.push({label: 'Teho keskimäärin', data: txt['sahko']['kulutusTunneittain'].map(i => (i / 10000) / (txt['meta']['tuntilaskuri'] / 24).toFixed(2)), borderWidth: 1, backgroundColor: "red", type: "line"});
        }


    if (kk) {
        kk.destroy();
        ulostaJava("TUHOTTIIN VANHA paikassa kulutusjakauma");
    } 
    kk = new Chart(ctx, {

        type: 'bar',
        data: {
          //labels: Utils.months({count: 24}),
          labels: Array.from({length: 24}, (v, k) => k++ + ":00"),
          datasets: dataset
        },
        options: {

            title: {
                    display: true,
                    text: 'Kellon aika',
                    position: 'bottom'

            },
            animation: false
        }
      });
      console.log(kk);
     }
     if (ylempiGraafi == "ilp_kulutus") {
        //const teho_keskimaarin = [];
        //teho_keskimaarin.fill(txt['ilp']['ilp_count_per_h'].reduce((a, b) => (a + b / 1000), 0) / txt['ilp']['ilp_count_per_h'].length);
        dataset.push({label: 'Kulutus / kWh', data: txt['ilp']['ilp_count_per_h'].map(i => i / 1000), borderWidth: 1, pointRadius: 0, backgroundColor: "#33AEEF"});
        dataset.push({label: 'Ottoteho keskimäärin', data: Array(txt['ilp']['ilp_count_per_h'].length).fill(txt['ilp']['ilp_count_per_h'].reduce((a, b) => (a + b / 1000), 0) / txt['ilp']['ilp_count_per_h'].length), borderWidth: 1, pointRadius: 0, backgroundColor: "green", fill: true});
        //ulostaJava(teho_keskimaarin);
        //dataset.push({label: 'Teho keskimäärin', data: teho_keskimaarin, pointRadius: 0, type: 'line', fill: false, borderColor: 'red', borderWidth: 1, backgroundColor: "#33AEEF"});
        if (kk) {
            kk.destroy();
            ulostaJava("TUHOTTIIN VANHA paikassa ilp kulutus");
        } 

      kk = new Chart(ctx, {
        type: 'line',
        data: {
          labels: Array.from({length: txt['ilp']['ilp_count_per_h'].length}, (v, k) => k++),
          datasets: dataset
        },
        options: {
            animation: false
        }
      });
    }
    if (ylempiGraafi == "veden_kulutus") {      // Tapahtuu napista veden kulutus
        ulostaJava("veden kulutus");
        ////Lisätään näytettäviin kulutuksiin myös reaaliaikainen tieto mittariltä, kuluvalta päivältä

        txt['vesi_logi']['kylma_paivittain'].shift();   //Alussa tulee aina tyhjä jostain syystä, tässä ppoistetaan se
        txt['vesi_logi']['kylma_paivittain'].push(txt['vesi']['kylma_vesi_count'] / 6.6 / 60);
        txt['vesi_logi']['lammin_paivittain'].shift();
        txt['vesi_logi']['lammin_paivittain'].push(txt['vesi']['ulkokierto_count'] / 11 / 60);
        let vesi_x_label = Array.from({length: txt['vesi_logi']['kylma_paivittain'].length - 1}, (v, k) => k + 1);
        vesi_x_label.push("Tänään");
        //let vesi_yhteensa = txt['vesi_logi']['kylma_paivittain'].map((a, i) => a + txt['vesi_logi']['lammin_paivittain'][i]);
        //console.log(vesi_yhteensa);
        
        ////////
        
        
        
        dataset.push({label: 'Kylmä vesi', data: txt['vesi_logi']['kylma_paivittain'].map(i =>  i.toFixed(0)), borderWidth: 1, pointRadius: 0, backgroundColor: "blue", stack: 'Stack 0'});
        dataset.push({label: 'Kuuma vesi', data: txt['vesi_logi']['lammin_paivittain'].map(i =>  i.toFixed(0)), borderWidth: 1, pointRadius: 0, backgroundColor: "red", stack: 'Stack 0'});
        //dataset.push({label: 'Yhteensä', data: vesi_yhteensa.map(i => i.toFixed(0)), borderWidth: 1, pointRadius: 0, backgroundColor: "yellow", stack: 'Stack 0'});

        if (kk) { //tuhotaan aiempi canvas ainoastaa, jos sellainen on aiemmin luotu
            kk.destroy();
            ulostaJava("TUHOTTIIN VANHA paikassa veden kulutus");
        } 
      kk = new Chart(ctx, {
        type: 'bar',
        data: {
          //labels: Array.from({length: txt['vesi_logi']['kylma_paivittain'].length}, (v, k) => k + 1),
          labels: vesi_x_label,
          datasets: dataset
        },
        options: {
            scales: {
                x: {
                    stacked: true,
                    title: {
                        color: 'green',
                        display: true,
                        text: 'Päivä'
                    }
                },
                y: {stacked: true}
            },
            animation: false
        }
      });
    }
//txt['vesi_logi']['kylma_paivittain'].map(i =>  i.toFixed(0))
    txt['ilp']['sisalampo'].shift();
    txt['ilp']['ulkolampo'].shift();
    txt['ilp']['sisa_puhallus'].shift();
    txt['ilp']['parvi'].shift();
    for (i = 0; i < txt['ilp']['ilp_ottoteho_log'].length; i++) {
        if (txt['ilp']['ilp_ottoteho_log'][i] > 3) {
            txt['ilp']['ilp_ottoteho_log'][i] = txt['ilp']['ilp_ottoteho_log'][i - 1];
            ulostaJava(txt['ilp']['ilp_ottoteho_log'][i]);
        }
    }
    if (kk_lampo) {
        kk_lampo.destroy();
    }


   const dataset_lammot = [];
   var labels_lammot = [];
   const ctx_h = document.getElementById('lammot');
   if (lampoGraafi == "kaikki") {
       dataset_lammot.push({label: 'Huonelämpö', data: txt['ilp']['sisalampo'], borderWidth: 1, pointRadius: 0, borderColor: "green", fill: false});
       dataset_lammot.push({label: 'Imulämpö parvella', data: txt['ilp']['parvi'], borderWidth: 1, pointRadius: 0, borderColor: "magenta", fill: false});
       dataset_lammot.push({label: 'Puhalluslämpö parvella', data: txt['ilp']['sisa_puhallus'], borderWidth: 1, pointRadius: 0, borderColor: "red", fill: false});
       dataset_lammot.push({label: 'Ulkolämpö', tension: 0, data: txt['ilp']['ulkolampo'], borderWidth: 1, pointRadius: 1, borderColor: "blue", fill: false});
       dataset_lammot.push({label: 'Ottoteho awg/min', type: 'bar', tension: 0, data: txt['ilp']['ilp_ottoteho_log'].map(i => i * 10), borderWidth: 1, pointRadius: 0, borderColor: "brown", fill: false});
       dataset_lammot.push({label: 'Ulkokierron paluu', data: txt['vesi_logi']['kierron_paluulampo'], borderWidth: 1, pointRadius: 0, borderColor: "magenta", fill: false});
       dataset_lammot.push({label: 'Pöntön lämpötila', data: txt['vesi_logi']['ponton_lampotila'], borderWidth: 1, pointRadius: 0, borderColor: "magenta", fill: false});
       dataset_lammot.push({label: 'Raakaveden lämpötila', data: txt['vesi_logi']['kierron_menolampo'], borderWidth: 1, pointRadius: 0, borderColor: "green", fill: false});


       labels_lammot = (Array.from({length: txt['ilp']['sisalampo'].length}, (v, k) => k++));
    }
    if (lampoGraafi == "viimeisin_tunti") {
       dataset_lammot.push({label: 'Huonelämpö', data: txt['ilp']['sisalampo'].slice(-60), borderWidth: 1, pointRadius: 0, borderColor: "green", fill: false});
       dataset_lammot.push({label: 'Imulämpö parvella', data: txt['ilp']['parvi'].slice(-60), borderWidth: 1, pointRadius: 0, borderColor: "magenta", fill: false});
       dataset_lammot.push({label: 'Puhalluslämpö parvella', data: txt['ilp']['sisa_puhallus'].slice(-60), borderWidth: 1, pointRadius: 0, borderColor: "red", fill: false});
       dataset_lammot.push({label: 'Ulkolämpö', tension: 0, data: txt['ilp']['ulkolampo'].slice(-60), borderWidth: 1, pointRadius: 1, borderColor: "blue", fill: false});
       dataset_lammot.push({label: 'Ottoteho awg/min', type: 'bar', tension: 0, data: txt['ilp']['ilp_ottoteho_log'].map(i => i * 1).slice(-60), borderWidth: 1, pointRadius: 0, borderColor: "brown", fill: false});
       dataset_lammot.push({label: 'Ulkokierron paluu', data: txt['vesi_logi']['kierron_paluulampo'].slice(-60), borderWidth: 1, pointRadius: 0, borderColor: "magenta", fill: false});
       dataset_lammot.push({label: 'Pöntön lämpötila', data: txt['vesi_logi']['ponton_lampotila'], borderWidth: 1, pointRadius: 0, borderColor: "magenta", fill: false});
       dataset_lammot.push({label: 'Raakaveden lämpötila', data: txt['vesi_logi']['kierron_menolampo'], borderWidth: 1, pointRadius: 0, borderColor: "green", fill: false});

       labels_lammot = (Array.from({length: 60}, (v, k) => k++));
    }

  kk_lampo = new Chart(ctx_h, {
    type: 'line',
    data: {
      labels: labels_lammot,
      //labels: Array.from({length: txt['ilp']['sisalampo'].length}, (v, k) => k++),
      
      datasets: dataset_lammot,
      options: {
        scales: {
            x: {
                type: 'linear',
                grace: '5%'
             }
         }
      }
     }
});






    /*
    var ilpLayout = {
        title: "ILP kulutus",
        xaxis: {
            title: "Aika"
        },
        yaxis: {
            title: "Kulutus per h",
        }
    }
    var ilp_kulutus_tunneittain;
    console.log(txt['ilp']['ilp_count_per_h'].slice(-d.getHours()));
    var ilp_data = [
      {
        x: 0,
        y: txt['ilp']['ilp_count_per_h'].map(i => i / 1000),
        type: 'line'
      },
      {
        x: 0,
        y: Array(txt['ilp']['ilp_count_per_h'].length).fill(txt['ilp']['ilp_count_per_h'].reduce((a, b) => (a + b / 1000), 0) / txt['ilp']['ilp_count_per_h'].length),
        type: 'line',
        name: 'teho keskimäärin'
      }
      
    ];

    Plotly.newPlot("ILP", ilp_data, ilpLayout);*/





   /* var vesiLayout = {
        title: "Water consumption",
        xaxis: {
            title: "Day",
        },
        yaxis: {
            title: "Liters per day",
        },
        images: [
           {
            x: 0,
            y: 0,
            sizex: 1,
            sizey: 1,
            xanchor: "left",
            xref: "paper",
            yanchor: "bottom",
            yref: "paper",
            opacity: 0.2
            }
        ]

    };
    var vesi_data = [
      {
        x: 0,
        y: (txt['vesi_logi']['kylma_paivittain'].map(i =>  i.toFixed(0))),
        type: 'bar',
        name: "Cold ",
        marker: {color: 'blue'}
      },
      {
        x: 0,
        y: (txt['vesi_logi']['lammin_paivittain'].map(i =>  i.toFixed(0))),
        type: 'bar',
        name: "Kuuma ",
        marker: {color: 'red'}
      }


      
    ];

    //Plotly.newPlot("vesi", vesi_data, vesiLayout);*/
    

      //},
      //{
        //x: 0,
        //y: (txt['ilp']['ilp_ottoteho_log'].map(i => i * 10 )),
        //type: 'bar',
        //name: "Ottoteho spot ",
        //marker: {color: 'orange'}
        //}

    

}


var data = 0;

function hae_kaikki_data() {
    data = fetch('/nayttopaate66/kaikki_data')
        .then(response => response.json())
        .then(data =>  sahkon_hinta(data));
}
hae_kaikki_data();
//setInterval(hae_kaikki_data, 60000);
</script>

Katso myös