Okay, have added the available data through to the end of July 2025. Now, I want to look at adding the current day’s rainfall data to the database. Well, assuming there is any rainfall to be recorded. As mentioned previously, this is something that will need to be done on a routine basis to keep the database up to date. In the end, it will likely be done through the dashboard, but for development purposes I will do so via the command line.

New Module

I couldn’t see to which existing module this new function/method should be added. So, I am, for now, going to create a new module, dshbd_utils.py and put it in there. I will use the __main__ block to get the required data from the command line when the module is executed in the terminal.

At this time I am not going to create a class of any sort. Just functions and calling code.

New Function

Okay, let’s get to coding this new function, add_daily_rf(). I originally thought that, via the dashboard, the code would simply assume the rainfall amount was for the period ending 08:00 that day. But you know, I may have missed a day or the reading is for a different time (e.g. the end of the day, commonly for the last day of the month). And, during testing I will be entering a number of daily rainfall amounts for August.

So, the function will have parameters for the date, time and rainfall amount (or rainfall equivalent if dealing with snow). I may provide defaults for the date (i.e. use today’s date) and time (08:00 my normal time for many years).

I am also thinking the function will get the current month-to-date rainfall total from the database and update that before calling the Weather_db class method to save the day’s data to the database.

I am currently not sure how I will handle getting the data for the function in the dashboard versus the command line. Should that be part of the function’s function or not? Thinking not. But…

Small steps.

# dshbd_utils.py: module for various dashboard utility functions
# ver: 0.1.0, 2025.08.27, rek, init version

import time
from pathlib import Path
import sqlite3
import pandas as pd

# module functions
# add_daily_rf(d_rf, m_rf, dt_rf="", tm_rf="08:00")

# module variables


def add_daily_rf(d_rf, m_rf, dt_rf="", tm_rf="08:00"):
  # if no date given, get today's date
  if not dt_rf:
    rf_dt = time.strftime("%Y.%m.%d", time.gmtime())
  else:
    rf_dt = dt_rf
  print(f'add_daily_rf({d_rf}, {m_rf}, dt_rf="{dt_rf}", tm_rf="{tm_rf}") -> "{rf_dt} {tm_rf}"')


if __name__ == "__main__":
  # simple tests of module code
  add_daily_rf(2.5, 5.5, "2025.08.12")
  add_daily_rf(4.5, 125.5)
  add_daily_rf(5.5, 140.5, "2025.08.31", tm_rf="24:00")

And, in the terminal I got the following. Which looks about right. (Note: at the time of working on this draft, it was August 27.)

(dbd-3.13) PS R:\learn\dashboard\utils> python dshbd_utils.py
add_daily_rf(2.5, 5.5, dt_rf="2025.08.12", tm_rf="08:00") -> "2025.08.12 08:00"
add_daily_rf(4.5, 125.5, dt_rf="", tm_rf="08:00") -> "2025.08.27 08:00"
add_daily_rf(5.5, 140.5, dt_rf="2025.08.31", tm_rf="24:00") -> "2025.08.31 24:00"

Re-think!

As I was working on the code for this function, I realized I was nuts to do so. I am going to end up calling the Weather_db method add_rainfall from within the function. So the only thing the function was doing was figuring out the date if one wasn’t supplied. I can just do that in the code being run to get a new day’s rainfall. Or require the user to supply it.

So I am going to write a function to get the date, time and rainfall amount from the user at the command line. In “main” I will call that function to get the data, then use that to update the database table. I will use real data for the month of August 2025, so will in fact update the current database.

Before going there here’s my test code. Wrote query to get current month’s total rainfall to-date. Will need to add or refactor method in Weather_db class to do that.

I added the rainfall for the month to an empty database to make sure it worked. I manually edited the index for the data lists.

if __name__ == "__main__":
  # instantiate database class
  cwd = Path(__file__).cwd()
  fl_pth = cwd/"../data"
  fl_nm = "weather.db"
  db_pth = fl_pth/fl_nm
  wdb = Weather_db(db_pth)

  tnm = wdb.tnms["rf_tnm"]
  tmp_dt = ["2025.08.06 08:00", "2025.08.07 08:00", "2025.08.15 08:00", "2025.08.16 08:00", "2025.08.17 08:00"]
  tmp_drf = [19.5, 1.5, 23.5, 51.5, 4.0]

  d_ndx = 4  
  c_mon = tmp_dt[d_ndx][:7]
  # get current month-to-date rainfall for appropriate month
  q_mtd = f"""SELECT MAX(monthly) FROM {tnm}
    WHERE datetime LIKE '{c_mon}%'"""
  qr_mtd = wdb.qry_exec(q_mtd)
  print(f"month to date rainfall: {qr_mtd[0][0]}")
  c_mtd = 0.0
  if qr_mtd[0][0]:
    c_mtd = round(float(qr_mtd[0][0]), 2)
  print(f"\t-> {c_mtd}")

  dly = (tmp_dt[d_ndx], tmp_drf[d_ndx], c_mtd + tmp_drf[d_ndx])
  print(f"inserting {dly}")
  n_rws = wdb.add_rainfall(dly)
 
  qr_mtd = wdb.qry_exec(q_mtd)
  print(f"rows added: {n_rws}, month to date rainfall: {qr_mtd[0][0]}")

And, those 5 executions resulted in the following in the terminal.

(dbd-3.13) PS R:\learn\dashboard\utils> python dshbd_utils.py
month to date rainfall: None
        -> 0.0
inserting ('2025.08.06 08:00', 19.5, 19.5)
rows added: 1, month to date rainfall: 19.5
(dbd-3.13) PS R:\learn\dashboard\utils> python dshbd_utils.py
month to date rainfall: 19.5
        -> 19.5
inserting ('2025.08.07 08:00', 1.5, 21.0)
rows added: 1, month to date rainfall: 21.0
(dbd-3.13) PS R:\learn\dashboard\utils> python dshbd_utils.py
month to date rainfall: 21.0
        -> 21.0
inserting ('2025.08.15 08:00', 23.5, 44.5)
rows added: 1, month to date rainfall: 44.5
(dbd-3.13) PS R:\learn\dashboard\utils> python dshbd_utils.py
month to date rainfall: 44.5
        -> 44.5
inserting ('2025.08.16 08:00', 51.5, 96.0)
rows added: 1, month to date rainfall: 96.0
(dbd-3.13) PS R:\learn\dashboard\utils> python dshbd_utils.py
month to date rainfall: 96.0
        -> 96.0
inserting ('2025.08.17 08:00', 4.0, 100.0)
rows added: 1, month to date rainfall: 100.0

Get New Rainfall Data at Command Line

I am not particularly creative at the command line, so I am going to ask for the date and time followed by the rainfall amount. No fancy colours or such. I am going to use argparse as I may just use this code as a command line utility to add daily rainfall to the database. That way I can do so without needing to run the dashboard. And, it will sort of help me if I do add the functionality to the dashboard code.

So I think I am going to start another module called get_daily_rf.py. This will be my command line utility for adding new daily rainfall data.

Get argparse Working

The first step is to get argparse instantiated and setup. I am going to do this in a function, as I want to be able to add a default date, the current date, to the appropriate parameter. In the test code, I will get the parser by calling the function, then take a look at what was passed at the command line.

The rainfall in mm is a required, positional argument. --date and --time are optional. Both with default values. The one for the date being today’s date as calculated in the function creating the parser.

# get_daily_rf.py: utility module to obtain daily rainfall data
#     and write it to the database
# ver: 0.1.0, 2025.08.29, rek, init version
#       will initially use argparse to get data as command line parameters
#       may eventually modify to also allow ui like interface

import argparse, time
from pathlib import Path
import pandas as pd

if __name__ == "__main__":
  from weather_db import Weather_db

def get_rf_parser():
  """Create and return parser for rainfall data.
  """
  # determine default date for optional parameter
  def_dt = time.strftime("%Y.%m.%d", time.gmtime())
  # instantiate and set up command paramter parser
  parser = argparse.ArgumentParser()
  parser.add_argument("-d", "--date", help="Supply date rainfall recorded, yyyy.mm.dd",
                      default=def_dt)
  parser.add_argument("-t", "--time", help="Supply time rainfall recorded (24 hour format), hh:mm",
                      default="08:00")
  parser.add_argument("rainfall", help="Supply amount of rainfall recorded (mm), 2 decimals maximum",
                      type=float)
  return(parser)


if __name__ == "__main__":
  # instantiate database class
  cwd = Path(__file__).cwd()
  fl_pth = cwd/"../data"
  fl_nm = "weather.db"
  db_pth = fl_pth/fl_nm
  wdb = Weather_db(db_pth)

  rf_dt, rf_tm, rf_rf = "", "", 0.0

  rf_parse = get_rf_parser()
  rf_args = rf_parse.parse_args()

  print(f"args: {rf_args}")
  rf_rf = round(rf_args.rainfall, 2)
  rf_dt = rf_args.date
  rf_tm = rf_args.time
  print(rf_rf, rf_dt, rf_tm)

And, some tests. Note: the date when I was working on this portion of the draft post was 2025.08.29.

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py
usage: get_daily_rf.py [-h] [-d DATE] [-t TIME] rainfall
get_daily_rf.py: error: the following arguments are required: rainfall
(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 19.5
args: Namespace(date='2025.08.29', time='08:00', rainfall=19.5)
19.5 2025.08.29 08:00
(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 0
args: Namespace(date='2025.08.29', time='08:00', rainfall=0.0)
0.0 2025.08.29 08:00
(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 19.5 -d 2025.08.06
args: Namespace(date='2025.08.06', time='08:00', rainfall=19.5)
19.5 2025.08.06 08:00
(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 19.5 -d 2025.08.06 -t 24:00
args: Namespace(date='2025.08.06', time='24:00', rainfall=19.5)
19.5 2025.08.06 24:00

New Database Method

I am going to add a method to the database class that will return the current month to-date rainfall. Pretty straightforward

  def get_mon_todt(self, yr_mn):
    """Get the current month to date value for the specified month.
       Full or partial month.

      Param:
        yr_mn: specifies the month, 'yyyy.mm'
    
      Returns:
        month to-date
    """
    q_mtd = f"""SELECT MAX(monthly) FROM {self.tnms["rf_tnm"]}
      WHERE datetime LIKE '{yr_mn}%'"""
    qr_mtd = self.qry_exec(q_mtd)
    if qr_mtd[0][0]:
      return round(float(qr_mtd[0][0]), 2)
    else:
      return 0

And a quick test of the new method.

... ...
  mtd = wdb.get_mon_todt(rf_dt[:7])
  print(f"{rf_dt[:7]} month to date: {mtd}")
(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 0
args: Namespace(date='2025.08.29', time='08:00', rainfall=0.0)
0.0 2025.08.29 08:00
2025.08 month to date: 100.0

Add Supplied Data to Database

Okay, on to the last bit of code. I really need to decide whether to allow the recording of 0 mm of rainfall. I am thinking only if no current data for the month and the entry is for the last day of the month and 24:00 hours.

Zero Rainfall OK?

Okay, I am going to allow a zero rainfall entry if it is for 24:00 on the last day of the month, and the current total monthly rainfall is zero. Since I know that I will already have the total rainfall for the month I am going to pass that as one of the arguments.

... ...
def allow_zero(dt, tm, mtd):
  rf_dt = datetime.strptime(f"{dt}", "%Y.%m.%d")
  mon_last = calendar.monthrange(rf_dt.year, rf_dt.month)[1]
  is_last = mon_last == rf_dt.day
  is_ok = is_last and (tm == "24:00") and (mtd == 0.0)
  return is_ok

And in my main code, I added the following.

... ...
# add data to database rainfall table, if appropriate
  zero_ok = allow_zero(rf_dt, rf_tm, mtd)
  print(f"('{rf_dt} {rf_tm}', rf_rf, mtd + rf_rf) -> zero_ok: {zero_ok}")

  if rf_rf or zero_ok:
    n_rws = wdb.add_rainfall((f"{rf_dt} {rf_tm}", rf_rf, mtd + rf_rf))

Here’s a few test runs.

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 0 -d 2025.08.31 -t 24:00
args: Namespace(date='2025.08.31', time='24:00', rainfall=0.0)
0.0 2025.08.31 24:00
2025.08 month to date: 100.0
('2025.08.31 24:00', rf_rf, mtd + rf_rf) -> zero_ok: False
Empty DataFrame
Columns: [row_id, datetime, daily, monthly]
Index: []

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 0 -d 2025.09.30 -t 24:00
args: Namespace(date='2025.09.30', time='24:00', rainfall=0.0)
0.0 2025.09.30 24:00
2025.09 month to date: 0
('2025.09.30 24:00', rf_rf, mtd + rf_rf) -> zero_ok: True
   row_id          datetime  daily  monthly
0      10  2025.09.30 24:00    0.0      0.0

And as you can see, a zero rainfall was entered for 2025.09.30 24:00.

Update Database

I am now going to update the actual database. Have been developing on a new empty one. And here’s the terminal output. I started with a couple of tests to see what was currently in the database for July and August. In order to check how things were proceeding, I also modified the query I was using to show all rows for the month in the date.

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 0 -d 2025.07.22
args: Namespace(date='2025.07.22', time='08:00', rainfall=0.0)
2025.07 month to date: 18.5
('2025.07.22 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
   row_id          datetime  daily  monthly
0    1768  2025.07.09 08:00   11.5     11.5
1    1769  2025.07.10 08:00    7.0     18.5

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 0
args: Namespace(date='2025.08.29', time='08:00', rainfall=0.0)
0.0 2025.08.29 08:00
('2025.08.29 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
Empty DataFrame
Columns: [row_id, datetime, daily, monthly]
Index: []

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 19.5 -d 2025.08.06
args: Namespace(date='2025.08.06', time='08:00', rainfall=19.5)
19.5 2025.08.06 08:00
2025.08 month to date: 0
('2025.08.06 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
0    1770  2025.08.06 08:00   19.5     19.5

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 1.5 -d 2025.08.07
args: Namespace(date='2025.08.07', time='08:00', rainfall=1.5)
1.5 2025.08.07 08:00
2025.08 month to date: 19.5

('2025.08.07 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
   row_id          datetime  daily  monthly
0    1770  2025.08.06 08:00   19.5     19.5
1    1771  2025.08.07 08:00    1.5     21.0

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 23.5 -d 2025.08.15
args: Namespace(date='2025.08.15', time='08:00', rainfall=23.5)
23.5 2025.08.15 08:00
2025.08 month to date: 21.0
('2025.08.15 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
   row_id          datetime  daily  monthly
0    1770  2025.08.06 08:00   19.5     19.5
1    1771  2025.08.07 08:00    1.5     21.0
2    1772  2025.08.15 08:00   23.5     44.5

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 51.5 -d 2025.08.16
args: Namespace(date='2025.08.16', time='08:00', rainfall=51.5)
51.5 2025.08.16 08:00
2025.08 month to date: 44.5
('2025.08.16 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
   row_id          datetime  daily  monthly
0    1770  2025.08.06 08:00   19.5     19.5
1    1771  2025.08.07 08:00    1.5     21.0
2    1772  2025.08.15 08:00   23.5     44.5
3    1773  2025.08.16 08:00   51.5     96.0

(dbd-3.13) PS R:\learn\dashboard\utils> python get_daily_rf.py 4.0 -d 2025.08.17
args: Namespace(date='2025.08.17', time='08:00', rainfall=4.0)
4.0 2025.08.17 08:00
2025.08 month to date: 96.0
('2025.08.17 08:00', rf_rf, mtd + rf_rf) -> zero_ok: False
   row_id          datetime  daily  monthly
0    1770  2025.08.06 08:00   19.5     19.5
1    1771  2025.08.07 08:00    1.5     21.0
2    1772  2025.08.15 08:00   23.5     44.5
3    1773  2025.08.16 08:00   51.5     96.0
4    1774  2025.08.17 08:00    4.0    100.0

And, that appears to work as desired.

That’s It

Well I think that’s it for this one. Sorted some new methods and functions. Made a decision regarding 0 mm rainfall records. Got something I can actually use from the command line to update the rainfall amounts in the weather database as needed, a day at a time.

A bit of debugging, a bit of refactoring and a bit of fun.

Until next time, be safe and take time out to have some fun.