Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 18:37 20 Nov 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Network UPS Tools (NUT) monitor using Micromite/Picomite

Author Message
MikeO
Senior Member

Joined: 11/09/2011
Location: Australia
Posts: 275
Posted: 04:17am 25 Mar 2022
Copy link to clipboard 
Print this post

If you have constructed a UPS that does not have a network connection or even an old mains powered unit, here is a serial software driver using MMBasic. The software was ported from an Arduino design, the ref is in the code header.

 '  ' ***** upsnut *****
 ' *******************************
 '    Filename: upsnut-mm.bas
 '    Date: Mar 2022
 '    File Version:
 '     Written by: M.Ogden
 '    Function: UPS NUT Tools hardware driver
 '   Device: micromite mx170, picomite
 '    Last Revision:
 '    Initial v0.5
 ' Based on Megatec UPS emulation for use with NUT UPS software
 ' on Raspberry Pi , by Mike Waldron
 ' See https://github.com/xm381/Raspberry-Pi-UPS
 ' *******************************
 'IO Pin List
 'Set for your hardware
 dim Vin_pin = A7
 dim Vout_pin = A0
 dim Vbat_pin = A6
 dim LBO_pin = A2
 dim Vout_Enable_pin = A3
 '
 
 Dim float Bsoc
 
 Dim Integer  LBO 'hardware low battery (has no hysteresis): low = low battery
 
 dim float Vin=12.2
 dim float Vout=5.2
 dim float Vbat=12.2
 Dim Integer LowBat = 0 'software low battery
 Dim Integer DeadBat = 0
 Dim Integer Vin_Fail = 0
 
 Dim integer Starting_Up = 0
 Dim integer Running = 1
 Dim integer Low_Battery = 2
 Dim integer Shutting_Down = 3
 Dim integer Shutdown = 4
 Dim integer ShutdownCommand = 5
 Dim integer RestartCommand = 6
 
 Dim Integer State = Starting_Up
 
 Dim Integer  Vout_Enable = 0
 Dim Integer Beeper_Enable = 1
 Dim Integer LED = 0
 
 Dim Integer Command_Shutdown = 0
 Dim Integer Command_Restart = 0
 
 
 Dim String inputString = ""    ' a string to hold incoming data
 Dim Integer stringComplete = 0 ' whether the string is complete
 
 'UPS Rating Information
 Dim float UPS_RV = 5.2 'Rated Voltage
 Dim float UPS_RC = 1.3 'Rated Current
 Dim float UPS_BV = 3.7 'Rated Voltage
 Dim integer UPS_HZ = 0.0 'Rated Frequency
 
 ' Hysteresis for software lowbat
 Dim integer LowBat_Max = 3.60
 Dim integer LowBat_Min = 3.55
 Dim integer Dead_Bat = 3.50
 
 Dim Integer Startup_Delay = 10
 Dim Integer Shutdown_Delay = 60
 Dim Integer Restart_Delay = 0
 Dim Integer secs
 '********************* Change these values as needed ***********************/
 dim header$="( "
 
 Dim string Company_Name ="Raspberry Pi   " '15 characters, leave space if less than 15 characters
 Dim string UPS_Model ="Pi UPS    " '10 characters, leave space if less than 10 characters
 Dim string CodeName ="UPSNUT "
 Dim string Version ="v1.0      " '10 characters, leave space if less than 10 characters
 
 
 '************ Set this section up for your hardware  
 '  pinMode(Vin_pin, INPUT)            ' Analog pin to measure input voltage (utility)
 '  pinMode(Vout_pin, INPUT)           ' Analog pin to measure output voltage
 '  pinMode(Vbat_pin, INPUT)           ' Analog pin to measure battery voltage
 '  pinMode(LBO_pin, INPUT_PULLUP)     ' Digital pin to read low battery signal
 '
 '  pinMode(Vout_Enable_pin, OUTPUT)   ' Digital pin to turn on output
 '  digitalWrite(Vout_Enable_pin, LOW)
 '
 '  pinMode(LED_BUILTIN, OUTPUT)       ' Digital pin to iluminate Pin 13 LED durring UPS restart timeout
 
 'serial Com1
 setpin gp0,gp1,com1
 open "com1:2400" as #5
 SetTick 1000, T1,1  '1 sec secs
 
 Print codename+version
 
 'main loop processing
 Do
   rec1
   
 Loop
 
 '************************ Core Subs *****************
 
Sub T1
 UPS_Status()
 UPS_State()
 
 secs = secs + 1
 
 if State = Shutting_Down then
   State = ShutdownCommand)
   'LED = !LED else LED= false
 end if
 if State = Starting_Up then LED = 1
 if (State = RestartCommand) and (Restart_Delay >0) then LED = 1
 
 'digitalWrite(LED_BUILTIN, LED)
 
End Sub
 
Sub rec1
 'reads bytes from comms buffer , data terminated by CR will output a NewLine$ and set the UserFlag
 'if userprocessflag=1 then exit sub
 Local a$
 Local Integer p,l,i
 ' Print "Buffer:";loc(5)
 If Loc(5)=0 Then Exit Sub
 If Len(a$)>=235 Then
   i=255-Len(a$)
 Else
   i=20
 EndIf
 'print "i:";i
 a$=Input$(i,5)  'user supplied processing routine
 'pause 100
 ' Print a$;
 On error skip 'DEBUG
 lastline$=lastline$ + a$    'add to data packet 'DEBUG
 '  Print  lastline$
packet:
 l=Len(lastline$)
 p=Instr(lastline$,Chr$(13))
 '  Print
 '  Print "Line Lenght:";l
 '  Print "CR?:";p
 '  Print "Buffer:";Loc(5)
 '  Print lastline$
 '  Print newline$
 '  Print
 '  '
 If l>=235 And p=0 Then   'long line and no CR
   'force line to be processed
   newline$=lastline$
   lastline$=""
   userprocess 'force data process
   Exit Sub
 EndIf
 
 If p>0 Then   'CR found so process
   'lastline$=replace$(lastline$,chr$(10),"")  'remove LF
   Newline$=Left$(Lastline$,p-1)
   'check comms using temperature string from Pi
   'if good reset the countdown clock
   If Instr(newline$,"{"+q$+"pi-temp"+q$+":")>0 Then cdclock=20
   If l>p+1 Then
     lastline$=Mid$(lastline$,p+1) 'save the rest of the line
   Else
     lastline$=""
   EndIf
   'recover standard data pairs from Pi
   Print "Process:";newline$
   userprocess
 EndIf
End Sub
 
 
Sub UPS_Status()
 ' Dummy values
 Vin = 15.6
 Vout = 5.2
 Vbat = 12.2
 lbo=1
 '************ Set this section up for your hardware  
 '  Vin = analogRead(Vin_pin) * 0.008 ' resistor divider halves voltage so double   value for correct reading, 0.008 for 4.096v reference.
 '  Vout = analogRead(Vout_pin) * 0.008 // resistor divider halves voltage so double value For correct reading, 0.008 For 4.096v reference.
 '  Vbat = analogRead(Vbat_pin) * 0.004 // 0.008 For 4.096v reference.
 '
 '  LBO = digitalRead(LBO_pin)
 
 If Vin < Vbat then
   Vin_Fail = 1
   
 Else
   Vin_Fail = 0
 end if
 
End Sub
 
Sub UPS_State()
 
 select case State
     
   Case 0  'Starting_Up
     If Vin_Fail =1 then
       State = Shutdown
       
     ElseIf (secs > Startup_Delay) then
       secs = 0
       Vout_Enable = 1
       State = Running
     end if
     
     
   Case 1  'Running
     If (Vin_Fail = 1) and (LowBat = 1) then
       State = Low_Battery
       secs = 0
     end if
     
   Case 2  'Low_Battery
     If DeadBat = 1 then
       State = Shutdown
       
     ElseIf LowBat = 0 then
       State = Running
       secs = 0
     end if
     
   Case 4  'Shutdown
     If Vin_Fail = 0 then
       State = Starting_Up
       secs = 0
     end if
     
   Case 5 'ShutdownCommand
     If secs > Shutdown_Delay then
       secs = 0
       Vout_Enable = 0
       State = RestartCommand
     end if
     
   Case 6  'RestartCommand
     If Restart_Delay = 0 then
       secs = 0
     ElseIf secs > Restart_Delay
       secs = 0
       Restart_Delay = 0
       Vout_Enable = 1
       State = Running
     end if
     
 end select
 
 'digitalWrite(Vout_Enable_pin, Vout_Enable)
End Sub
 
function constrain(v,a,b)
 If v>=a And v<=b Then
   constrain=v
 Else
   If v<a Then
     constrain=a
   Else
     constrain=b
   EndIf
 EndIf
End function
 
Sub userprocess
 
 '  Q1 Status Inquiry (MMM.M NNN.N PPP.P QQQ RR.R SS.S TT.T b7b6b5b4b3b2b1b0<cr>
 If  newline$ = "Q1" Then
   
   'print #5,  "215.0 195.0 230.0 014 49.0 2.27 30.0 00101000"
   
   
   print #5,  "( ";
   print #5,  Str$(Vin,3,1,"0");                  ' MMM.M Input voltage
   
   print #5,  " ";
   print #5,  Str$(Vin,3,1,"0");                  ' NNN.N Input fault voltage
   
   print #5,  " ";
   print #5,  Str$(Vout,3,1,"0");                  ' PPP.P Output voltage
   
   print #5,  " ";
   print #5,  "050";                    ' QQQ   Output current %
   
   print #5,  " ";
   print #5,  "00.0";                   ' RR.R  Input frequency
   
   print #5,  " ";
   print #5,  Str$(Vbat,1,2,"0");                  ' S.SS  Battery voltage
   
   print #5,  " ";
   print #5,  "21.1";                   ' TT.T  Temperature centigrade
   
   print #5,  " ";
   
   '   UPS Status Byte
   print #5,  Str$(Vin_Fail);          ' 7 Utility Fail (Immediate)
   print #5,  Str$(LowBat);            ' 6 Battery Low
   print #5,  Str$(Vin_Fail);          ' 5 Bypass/Boost or Buck Active
   print #5,  Str$(0);               ' 4 UPS Failed
   print #5,  Str$(1);               ' 3 UPS Type is Standby (0 is On_line)
   print #5,  Str$(0);               ' 2 Test in Progress
   
   If (State = Shutting_Down ) Then
     State = ShutdownCommand
     print #5,  "1";  ' 1 Shutdown Active
   Else
     print #5,  "0";
   EndIf
   print #5,  str$(Beeper_Enable)     ' 0 Beeper On
   
   '  S<n>R<m> Shut Down and Restore Command
 ElseIf (Left$(newline$,1)="S") And (Mid$(newline$,3,1)="R")Then  'and (val(mid$(newline$,4,1)>=0)) then
   '  elseif (inputString.startsWith("S") && inputString.indexOf("R") >= 0) then
   'Integer R_index = val(mid$(newline$,4,1))
   
   'String SD_delay = inputString.substring(1, R_index)
   Shutdown_Delay = Val(Mid$(newline$,2,1)) * 60
   Shutdown_Delay = constrain(Shutdown_Delay, 60,600) 'ensuring value is at least 1 minute
   
   'String RS_delay = inputString.substring(R_index + 1)
   Restart_Delay = Val(Mid$(newline$,4,1)) * 60
   
   If Restart_Delay > 0 Then
     Restart_Delay = constrain(Restart_Delay, 60, 36000) ' 1 minute to 10 hours (600 minutes)
     State = ShutdownCommand
   EndIf
   '  S<n> Shut Down Command
 ElseIf (Left$(newline$,1)="S") Then 'and (val(mid$(newline$,2,1)>0)) then
   
   Shutdown_Delay = Val(Mid$(newline$,2,1)) * 60
   Shutdown_Delay = constrain(Shutdown_Delay, 60, 600) 'ensuring value is at least 1 minute
   
   State = ShutdownCommand
   
   '  C Cancel Shut Down Command
 ElseIf Left$(newline$,1)="C" Then
   State = Running
   
   '  I UPS Information Command  #Company_Name UPS_Model Version<cr>
 ElseIf Left$(newline$,3)="I" Then
   print #5,  "#" + Company_Name +" "+ UPS_Model +" "+ Version
   
   
   '  F UPS Rating Information #MMM.M QQQ SS.SS RR.R<cr>
 ElseIf Left$(newline$,3)="F" Then
   print #5,  "#";
   print #5,  Str$(UPS_RV,3,1,"0");
   print #5,  " ";
   print #5,  Str$(UPS_RC,3,1,"0");
   print #5,  " ";
   print #5,  Str$(UPS_BV,2,2,"0");
   print #5,  " ";
   print #5,  Str$(UPS_HZ,2,1,"0");
   
   
   '  Q Turn On/Off beep
 ElseIf Left$(newline$,3) ="Q" Then
   if Beeper_Enable=1 then
     Beeper_Enable=0
   else
     Beeper_Enable=1
   end if
   
   
   '  ***** Unsupported Commands *****
   '  D Status Inquiry *disable
 ElseIf Left$(newline$,3) ="D" Then
   print #5,  "@"
   
   '  T 10 Seconds Test
   '  TL Test until Battery Low
   '  T<n> Test for Specified Time Period
 ElseIf (Left$(newline$,1)="T") Then
   print #5,  "@"
   
   '  CT Cancel Test Command
 ElseIf Left$(newline$,3)= "CT" Then
   print #5,  "@"
   
   '  ***** Custom Commands *****
 ElseIf Left$(newline$,2)= "MS") Then
   print #5,  "State:    "; str$(State)
   print #5,  "Startup:  "; str$(Startup_Delay)
   print #5,  "Shutdown: "; str$(Shutdown_Delay)
   print #5,  "Restart:  "; str$(Restart_Delay)
   
   ' Invalid command
 Else
   print #5,  newline$
   print #5,  ""
 EndIf
End Sub


Network query from attached Linux box.


mike@q4os-desktop:~/Desktop$ upsc RPUPS
Init SSL without certificate database
battery.charge: 100
battery.runtime: 3000
battery.voltage: 12.20
battery.voltage.high: 4.10
battery.voltage.low: 3.45
battery.voltage.nominal: 3.70
device.mfr: Raspberry Pi
device.model: Pi UPS
device.type: ups
driver.name: blazer_ser
driver.parameter.offdelay: 60
driver.parameter.ondelay: 1
driver.parameter.pollinterval: 2
driver.parameter.port: /dev/ttyUSB0
driver.parameter.runtimecal: 1500,100,3000,50
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.internal: 1.57
input.frequency: 0.0
input.voltage: 15.6
input.voltage.fault: 15.6
output.voltage: 5.2
ups.beeper.status: enabled
ups.delay.shutdown: 60
ups.delay.start: 60
ups.firmware: v1.0
ups.load: 50
ups.mfr: Raspberry Pi
ups.model: Pi UPS
ups.status: OL
ups.temperature: 21.1
ups.type: offline / line interactive
mike@q4os-desktop:~/Desktop$      


 

Codenquilts
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025