''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' experiment.bas
' A program to measure voltage and current at VK5RMG
Const vervk5dj = "1.39"
'
'Name of display variables in index.html must be at least the length of the content
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 
Option ESCAPE
Option EXPLICIT
Option Autorun On, NORESET

Const true = 1
Const false = 0
Const WatchDogOn = true          ' disable for debugging
If WatchDogOn Then WatchDog 20000


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' User changeable constants
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Const DefaultTimeZone = 9.5  ' this is the default timezone if the location is not set
Const LogToConsole = true    ' set to false if you do NOT want status messages printed to the console

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' I/O pins

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' general variables
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
 dim Integer i					   ' used in web interrupt
 dim String s
 dim DateStore01$   LENGTH 10	   'store date to hold old data in index.html
 dim DateStore02$   LENGTH 10
 dim DateStore03$   LENGTH 10
 dim DateStore04$   LENGTH 10
 dim DateStore05$   LENGTH 10
 dim DateStore06$   LENGTH 10
 dim DateStore07$   LENGTH 10
 dim DateStore08$   LENGTH 10
 
 dim TimeStore01$   LENGTH 8	   'store time to hold old data in index.html
 dim TimeStore02$   LENGTH 8
 dim TimeStore03$   LENGTH 8
 dim TimeStore04$   LENGTH 8
 dim TimeStore05$   LENGTH 8
 dim TimeStore06$   LENGTH 8
 dim TimeStore07$   LENGTH 8
 dim TimeStore08$   LENGTH 8
 
 dim BatteryVA001$ LENGTH 12		'store Load VA to hold immediate value in index.html (immediate value)
 dim BatteryVA002$ LENGTH 12		'next 7 values are old stored data for use in index.html 
 dim BatteryVA003$ LENGTH 12
 dim BatteryVA004$ LENGTH 12
 dim BatteryVA005$ LENGTH 12
 dim BatteryVA006$ LENGTH 12
 dim BatteryVA007$ LENGTH 12
 dim BatteryVA008$ LENGTH 12
 
 dim SolarVAmp001$ LENGTH 12		'store Solar VA to hold old data in index.html
 dim SolarVAmp002$ LENGTH 12
 dim SolarVAmp003$ LENGTH 12
 dim SolarVAmp004$ LENGTH 12
 dim SolarVAmp005$ LENGTH 12
 dim SolarVAmp006$ LENGTH 12
 dim SolarVAmp007$ LENGTH 12
 dim SolarVAmp008$ LENGTH 12
 
 dim PrintDate001$ LENGTH 12		'display current date etc in index.html
 dim PrintTime001$ LENGTH 8
 dim PrintLoadVA01$ LENGTH 11
 dim PrintSolarVA01$ LENGTH 11
 
 'now the print variables
  Dim PrintDate002$   LENGTH 12
  Dim PrintTime002$   LENGTH 8
  Dim PrintLoadVA02$  LENGTH 14 = "Six AM"
  DIM PrintSolarVA02$ LENGTH 14
  Dim PrintDate003$   LENGTH 14
  Dim PrintTime003$   LENGTH 8
  Dim PrintLoadVA03$  LENGTH 14 = "Nine AM"
  Dim PrintSolarVA03$ LENGTH 14 
  Dim PrintDate004$   LENGTH 14
  Dim PrintTime004$   LENGTH 8
  dim PrintLoadVA04$  LENGTH 14 = "Noon"
  Dim PrintSolarVA04$ LENGTH 14
  Dim PrintDate005$   LENGTH 14
  Dim PrintTime005$   LENGTH 8
  Dim PrintLoadVA05$  LENGTH 14 = "Three PM"
  Dim PrintSolarVA05$ LENGTH 14
  Dim PrintDate006$   LENGTH 14
  Dim PrintTime006$   LENGTH 8
  Dim PrintLoadVA06$  LENGTH 14 = "Six PM"
  Dim PrintSolarVA06$ LENGTH 14
  Dim PrintDate007$   LENGTH 14
  Dim PrintTime007$   LENGTH 8
  Dim PrintLoadVA07$  LENGTH 14 = "Nine PM"
  Dim PrintSolarVA07$ LENGTH 14 
  dim TempSolarV as float = 0.0			'the next 2 variables are used in the solar daily calculations
  dim TempSolarA as float = 0.0			'set values until system is working
  dim flipflop as integer = 0
  dim TempSt$ as string
  dim VoltsL$ LENGTH 6
  dim AmpsL$ LENGTH 6  
  dim VoltsS$ LENGTH 6
  dim AmpsS$ LENGTH 6
  dim float voltout			  'last of ANA226 variables
  dim float ampout
  dim VoltH as Integer
  dim VoltL as Integer
  dim Lamps as Integer  	  'load amps
  dim Samps as integer  	  'solar amps
  dim Lvolts as integer 	  'load volts
  dim Svolts as integer 	  'solar volts
  dim Temperature$ LENGTH 8   'print temp from DHT22
  dim HumidValue$ LENGTH 8    'print humidity as string
  dim temper as float		  'dimension input from HUMID command
  dim humidity as float        
  dim DateNow$ LENGTH 10	  'time calcs
  dim TimeNow$ LENGTH 8
  dim Mins$ LENGTH 2
  dim secs$ LENGTH 2
  dim Hrs$ LENGTH 2
  dim BootInf$ Length 20
  dim hours as Integer
  dim minutes as Integer
  dim seconds as Integer
  dim countB as Integer
 
  dim Bool as integer = 0	'used in allocation of old data
  dim Bool1 as integer = 0
  dim ReceivedBytes$ AS STRING*2
  dim PaddedString$ as string*2
  
  Dim dta%(1)				'hold two bytes for INA226 query
  Dim buf%(4096/8)			'the wifi buffer and number of connections
  
  dim BasicVersion as float 'get the basic version for index.html
  BasicVersion = MM.INFO(VERSION)  
  
  dim TempStr as String		'variables for power
  Dim Solartoday$ 	  LENGTH 10 
  Dim Solaryesterday$ LENGTH 10 
  Dim TempW!
  Dim StoreW!

 SETPIN 25, DOUT			'On pin p25 of pico interrupts the PIC on port B.0 and flashes LED
 SETPIN 20, DIN,pullup		'input 5V tolerant fires a save on PICO 20, from port B.1 on PIC portB.1 
 'Note: Pin 31 GP26 is used for the temp/humidity but is declared elsewhere
 '    : Pins 21,22 are I2C
 '    : Pin 30 reset pico, pin 36 is 3V3 out from pico, pin 20 cause save active high
 '	  : Pin 40 5V in, Pin 25 LED and pulses to PIC16F1827,
 '    : Pins 3,8,13,18,23,28,33,38 are Gnd
 WATCHDOG 40000			    'watchdog 40secs
 
 
''Set the timers
settick 2017,GetTempHumid,1	  'checks temp and humidity.
settick 491,Flipled,2		  'flips activity led
settick 3600007,CheckNTP,3     'check that internet working every hour
settick 300000, CalcSolarW,4  'calculate power every 5mins
  
Print "Checking connection to WiFi"
Timer = 0					'reset timer for next check	
Do While MM.Info(IP ADDRESS) = "0.0.0.0" 	'ensure there is a wifi connection
  WATCHDOG 40000
  If Timer >= 30000 Then 
	 Print "Network not found - Reboot" 
	 Pause 1500
	 CPU RESTART						'also resets Timer to 0
  else 
     if MM.Info(IP ADDRESS) = "0.0.0.0" Then Print "Waiting for WiFi"
  endif	 
  Pause 1000
Loop

Print "Connected.  IP address is " + MM.Info$(ip address)
Print "Getting UTC time"

Do
  Watchdog 40000				'after reboot
  On error skip
  WEB ntp + 9.5
  If MM.Errno <> 0 And Timer < 10000 Then Print "Waiting for the Internet Time server"
Loop Until MM.Errno = 0

' load all the config and setup values from the file A:/settings.dat
LoadAllConfigVars		'reload old measurements from settings.dat
pause 100
LoadSolarVars			'reload old solar from solar.dat

'write to the ANA 226 config initial settings and calibration on start
SETPIN 21,22,I2C		      'set the pins for I2C
i2c open 100,200			  'open I2C	
'now for first I2C number of $40
'note &H45,&H27 is Ave=16, Bus volt Conv=1100, Shunt Volt conv = 1100, Shunt and bus continuous

I2C WRITE &H40,&H00,&H03,&H00,&H45,&H27  'First need to write to the config register to set it up
I2C WRITE &H40,&H00,&H03,&H05,&H02,&H00  'set calibration for current register was 0204

 
'now for second I2C number of $41 original
 I2C WRITE &H41,&H00,&H03,&H00,&H45,&H27  'First need to write to the config register to set it up
 I2C WRITE &H41,&H00,&H03,&H05,&H02,&H00  'set calibration for current register &H05 

WEB TCP INTERRUPT WebInterrupt			   'send to WIFI interrupt

'__________________ Finish of general setup _________________________

' below is the main processing loop

Do
  WatchDog 40000 
  GetValues
  CreateData
  'extract the integers
  Hrs$ = mid$(Time$,1,2)    'access the clock
  Mins$ = mid$(Time$,4,2)
  Secs$ = mid$(Time$,7,2)
  hours = val(Hrs$)
  minutes = val(mins$)
  Seconds = val(secs$)
  WatchDog 40000 
Loop

Sub FlipLed					'led flash routine. Fired by "settick" every 500ms
	If Pin(25) = 1 then
	   pin(25) = 0
	else
	   pin(25) = 1
	endif 
end sub	   

 SUB CreateData       'creates the data for the display "Previous"     
 if Bool1 = 0 then
   if hours = 6 and minutes = 0 and seconds = 0 Then		'At 6.00AM
    GetValues
	PrintDate002$ = PrintDate001$
	PrintTime002$ = PrintTime001$
	PrintLoadVA02$ = PrintLoadVA01$
	PrintSolarVA02$ = PrintSolarVA01$
        bool1 = 1
	SaveAllConfigVars
 	SaveSolarVars

   endif
   if hours = 9 and minutes = 0 and seconds = 0 Then		'At 9:00AM
    GetValues 
	PrintDate003$ = PrintDate001$
	PrintTime003$ = PrintTime001$
	PrintLoadVA03$ = PrintLoadVA01$
	PrintSolarVA03$ = PrintSolarVA01$
    bool1 = 1
    SaveAllConfigVars
    SaveSolarVars
	
   endif
   if hours = 12 and minutes = 0 and seconds = 0 Then   	'Midday
    GetValues
	PrintDate004$ = PrintDate001$
	PrintTime004$ = PrintTime001$
	PrintLoadVA04$ = PrintLoadVA01$
	PrintSolarVA04$ = PrintSolarVA01$
	bool1 = 1
	SaveAllConfigVars
	SaveSolarVars
   endif
   if hours = 15 and minutes = 0 and seconds = 0 Then    	'Three pm
    GetValues 
	PrintDate005$ = PrintDate001$
	PrintTime005$ = PrintTime001$
	PrintLoadVA05$ = PrintLoadVA01$
	PrintSolarVA05$ = PrintSolarVA01$
	bool1 = 1
	SaveAllConfigVars
	SaveSolarVars
   endif
   if hours = 18 and minutes = 0 and seconds = 0 Then 		'Six PM
    GetValues
	PrintDate006$ = PrintDate001$
	PrintTime006$ = PrintTime001$
	PrintLoadVA06$ = PrintLoadVA01$
	PrintSolarVA06$ = PrintSolarVA01$
	bool1 = 1
	SaveAllConfigVars
	SaveSolarVars
   endif
   if hours = 21 and minutes = 0 and seconds = 0 Then       'nine pm
    GetValues
	PrintDate007$ = PrintDate001$
	PrintTime007$ = PrintTime001$
	PrintLoadVA07$ = PrintLoadVA01$
	PrintSolarVA07$ = PrintSolarVA01$
	bool1 = 1
	SaveAllConfigVars
	SaveSolarVars
   endif 	
   if hours = 1 and minutes = 0 and seconds = 0 Then
	bool1 =1
	FixSolarAt1AM										'transfer today watts to yesterday, reset today	
   endif
 endif 
 if seconds <> 0 then 									'reset the controlling flags
    bool = 0
	bool1 = 0
 endif	
 if pin(20) = 0 Then									'zero save solar variables
	SaveSolarVars
	DO WHILE Pin(20) = 0
	Loop												'wait for pin to return 1
	Print "Solar variables saved"
 endif
 END SUB 

 SUB GetINA226SetupLoad  
  
' Get load volts register 01 is the shunt voltage while 02 is the bus voltage. 04 is current register

  PAUSE 20							 'give ana226 time
  I2C WRITE &H40,&H00,&H01,&H02      'set up register $H02 ready for read of volts
  I2C Read &H40,&H00,&H02,dta%()     'read the volts
  voltout = dta%(1) + 256 * dta%(0)  'calculate volts from register
  voltout = voltout * 0.00125   	 'correct voltage- starting point 0.00125
  Tempst$ = format$(VoltOut,"%.1f")  'get the volts in string form to 1 dec place          
  voltsL$ = left$(TempSt$,4)		 'extract 4 digits from result
  PAUSE 20
  
 'now to read the load current
  I2C WRITE &H40,&H00,&H01,&H04      'set up register ready for read of current
  I2C Read &H40,&H00,&H02,dta%()     'get the current from register 04 into array
  ampout = dta%(1) + 256 * dta%(0)	 'calculate current from array	
  ampout = (ampout / 1000.0)         'change mA to A
  Tempst$ = format$(Ampout,"%.1f")   'format the current to 1 dec places in string
  AmpsL$ = left$(TempSt$,4)			 'extract 3 digits and a dot
'  print "Load: "voltsL$,"V ",Ampsl$,"A " 'Print volts/amps  on Tera Term

END SUB

SUB GetINA226SetupSolar 
'Get solar volts
'register 01 is the shunt voltage while 02 is the bus voltage. 04 is current register

  PAUSE 20						      'short delay to give encoder some breather time
  I2C WRITE &H41,&H00,&H01,&H02       'set up register $H02 ready for read of volts
  I2C Read &H41,&H00,&H02,dta%()      'read the volts from register  02  into array      
  voltout = dta%(1) + 256 * dta%(0)   'extract the volts from the array
  voltout = voltout * 0.00125		  'correct voltage- starting point 0.00125
  TempSolarV = voltout				  'used in solar power calcs
  Tempst$ = format$(VoltOut,"%.1f")   'get the volts in string form to 1 dec place          
  voltsS$ = left$(TempSt$,4)		  'extract 3 digits and a dot
 
 'now to read the solar current
  PAUSE 20						      'short delay to give encoder some breather time
  I2C WRITE &H41,&H00,&H01,&H04       'set up ready for read of current
  I2C Read &H41,&H00,&H02,dta%()      'get the current register 04 into array 
  ampout = dta%(1) + 256 * dta%(0)	  'calculate current from array		
  ampout = (ampout / 1000.0)		  'change mA to A
  TempSolarA = ampout				  'used in solar power calcs	
  Tempst$ = format$(Ampout,"%.1f")    'format the current to 2 dec places in string
  AmpsS$ = left$(TempSt$,4)			  'extract 4 digits and a dot

END SUB


SUB GetValues'this routine will query the INA226 device and build the variable for printing
  GetINA226SetupLoad
  GetINA226SetupSolar		
  PrintDate001$ = Date$+"/"
  PrintTime001$ = Time$
  PrintLoadVA01$  = VoltsL$+"V/"+AmpsL$+"A"
  PrintSolarVA01$  = VoltsS$+"V/"+AmpsS$+"A" 
END SUB

Sub	GetTempHumid				       'queries the DHT11
  device HUMID GP26, Temper, humidity,0		'0=dht22, 1= dht11
  print "Temp= ",temper,"   Humid= ",humidity 
  if Temper <> 1000 then		       'sometimes DHT errors to 1000, this traps it
    Temperature$ = str$(Temper)
    HumidValue$ = str$(humidity)
  endif
  BootInf$ = mm.info$(boot)
END SUB

sub CheckNTP					'this is checked every hour to ensure network operational
  timer = 0
  countb = 0
Do
  On error skip
  WEB ntp + 9.5
  If MM.Errno <> 0 And Timer < 30000 Then Print "Waiting for the Internet Time server"
  inc countB
  Watchdog 40000
  pause 1000						'1sec between tries
  if countB >20 then
	Print "Timeout - Reboot"
    Pause 1500 
    CPU RESTART
  endif	
Loop Until MM.Errno = 0
pause 100
end sub

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' the code handling the web server
' it is all driven by interrupts from the web server
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' sub to handle all web server requests
Sub WebInterrupt
  Local integer a% ', pnbr, i, j, p, t		'added p,t
'  Local string name, value
 ' Timer = 0
  For a% = 1 To MM.Info(MAX CONNECTIONS)
    LongString CLEAR buf%()
	'Do While MM.Info(IP ADDRESS) = "0.0.0.0"
       'If Timer > 10000 Then Pause 5000 : CPU RESTART
       'Pause 1000
    ' Loop
	'LongString CLEAR buf%()
    WEB TCP READ a%, buf%()
    If LLen(buf%()) > 0 Then
        WEB TRANSMIT PAGE a%,"index.html",4096  
	Endif 
  Next a%
End Sub

Sub SaveAllConfigVars
  Print "Saving config and settings data to A:/settings.dat"
  Open "A:/settings.dat" For output As #1
  Print #1, PrintDate002$
  Print #1, PrintTime002$
  Print #1, PrintLoadVA02$
  Print #1, PrintSolarVA02$
  Print #1, PrintDate003$
  Print #1, PrintTime003$
  Print #1, PrintLoadVA03$
  Print #1, PrintSolarVA03$
  Print #1, PrintDate004$
  Print #1, PrintTime004$
  Print #1, PrintLoadVA04$
  Print #1, PrintSolarVA04$
  Print #1, PrintDate005$
  Print #1, PrintTime005$
  Print #1, PrintLoadVA05$
  Print #1, PrintSolarVA05$
  Print #1, PrintDate006$
  Print #1, PrintTime006$
  Print #1, PrintLoadVA06$
  Print #1, PrintSolarVA06$
  Print #1, PrintDate007$
  Print #1, PrintTime007$
  Print #1, PrintLoadVA07$
  Print #1, PrintSolarVA07$
  Close #1
End Sub

Sub LoadAllConfigVars
  On error skip
  Open "A:/settings.dat" For input As #1
  If MM.Errno Then
    Print "Cannot find file A:/settings.dat"
    Exit Sub
  EndIf
  Print "Loading settings data from A:/settings.dat"
  Line Input #1, PrintDate002$
  Line Input #1, PrintTime002$
  Line Input #1, PrintLoadVA02$
  Line Input #1, PrintSolarVA02$
  Line Input #1, PrintDate003$
  Line Input #1, PrintTime003$
  Line Input #1, PrintLoadVA03$
  Line Input #1, PrintSolarVA03$
  Line Input #1, PrintDate004$
  Line Input #1, PrintTime004$
  Line Input #1, PrintLoadVA04$
  Line Input #1, PrintSolarVA04$
  Line Input #1, PrintDate005$
  Line Input #1, PrintTime005$
  Line Input #1, PrintLoadVA05$
  Line Input #1, PrintSolarVA05$
  Line Input #1, PrintDate006$
  Line Input #1, PrintTime006$
  Line Input #1, PrintLoadVA06$
  Line Input #1, PrintSolarVA06$
  Line Input #1, PrintDate007$
  Line Input #1, PrintTime007$
  Line Input #1, PrintLoadVA07$
  Line Input #1, PrintSolarVA07$
  Close #1
  Print "Loaded config variables"
End Sub

Sub SaveSolarVars
  Print "Saving solar data to A:/solar.dat"
  Open "A:/solar.dat" For output As #2
  Print #2, SolarYesterday$			'save yesterday watt/hrs
  Print #2, SolarToday$				'save today's watt hrs
  Close #2
End Sub

Sub LoadSolarVars
  On error skip
  Open "A:/solar.dat" For input As #2
  If MM.Errno Then
    Print "Cannot find file A:/solar.dat"
    Exit Sub
  EndIf
  Print "Loading solar data from A:/solar.dat"
  Line Input #2, SolarYesterday$
  Line Input #2, SolarToday$
  StoreW! = Val(SolarToday$)  
  Close #2
  Print "Loaded solar data"
End Sub

Sub CalcSolarW								'call every 5 minute from pico
LOCAL tempamps as Integer
LOCAL tempvolts as integer
 	GetValues
        tempamps = val (AmpsS$)
	tempvolts = val(VoltsS$)
	TempW! = TempVolts * TempAmps / 12000   'kWh (Convert 5 min readings to kW)
	StoreW! = StoreW! + TempW!				'update days rolling variable
	Solartoday$ = format$(StoreW!,"%.3f")   'get the watt/hr in string form for today 
End Sub

Sub FixSolarAt1AM						    'called at 1AM from PICO
	SolarYesterday$ = SolarToday$			'save yesterday from last today watt/hrs
	Storew! = 0.0
	Solartoday$ = format$(StoreW!,"%.3f")   'get the watt/hr in string form zeroed for today 
	SaveSolarVars
	print "Solar information prepared and saved for next day"
End Sub	