Electricity Bills for a Housing Society
Slab-wise bills for every flat from a month's meter readings.
1Introduction: the problem it solves
A housing society secretary collects meter readings for forty flats and works out each bill on a calculator. Tariffs are slab-based — the first hundred units cost less than the next hundred — so every bill is four separate multiplications, and one slip means a resident is overcharged.
This is arithmetic with a rule book, which is the kind of job a program never gets wrong twice.
A housing society, a paying-guest owner billing tenants, or a shop billing sub-meters.
Why it is worth computerising
A slab tariff is designed to be fair, and the cost of that fairness is arithmetic. Each bill is four separate multiplications and an addition, and a society secretary does that forty times over with a calculator every month. One slip is not caught by anybody except the resident who was overcharged.
The rules never change between one flat and the next, which is exactly the condition under which a computer should be doing the work. Putting the tariff in one place has a second benefit: when the board revises a rate, one line is edited and every subsequent bill is correct, instead of forty calculations being re-learnt.
Objectives
- To read a month's meter readings for every flat from one file
- To work out the units used from the previous and current readings
- To charge each slab at its own rate, the way a real tariff does
- To add the fixed monthly charge and produce a printable bill for every flat
- To hold the tariff in one place, so a revision by the board is a one-line edit
2How the job is done today
Before writing anything it is worth asking how the work is handled at present, and why each of those answers falls short. These were examined:
What most societies do. Slab arithmetic done forty times over is where the errors come from, and a resident overcharged once stops trusting the whole exercise.
Comprehensive, subscription-priced, and built around accounting rather than meters. Small societies rarely buy it for this one job.
Common and fragile. The slab formula is hard to read, harder to check, and quietly wrong when the board changes a rate.
3Functionalities
- Reads previous and current readings for every flat from a CSV file
- Charges each slab at its own rate, the way a real tariff works
- Adds the fixed monthly charge
- Writes all the bills into one printable file
- Keeps the tariff in one list at the top, so a rate change is a one-line edit
The functions that provide them
| Function | Arguments | What it does |
|---|---|---|
units_cost() | units | Charge each slab at its own rate, the way a real tariff works. |
make_bills() | reading_file, bill_file | Read every flat's readings and write out a bill for each. |
4Technical details
| Language | Python 3 |
| Storage | Plain text and CSV files |
| Modules used |
|
5How the data is stored
`readings.csv` holds the flat, the resident's name, and the previous and current meter readings. `bills.txt` is the output. The tariff lives in the SLABS list, so when the board revises rates you edit one line rather than hunting through the code.
readings.csv — the input
| Field | Type | Description |
|---|---|---|
flat | text | Flat number, as it appears on the door |
name | text | Resident's name, printed on the bill |
previous | integer | Meter reading at the start of the month |
current | integer | Meter reading at the end of the month |
SLABS — the tariff held in the program
| Field | Type | Description |
|---|---|---|
limit | integer | Upper edge of the slab in units; None for the last one |
rate | decimal | Rupees per unit charged inside that slab |
FIXED | decimal | Fixed monthly charge added to every bill |
Sample contents of readings.csv
| flat | name | previous | current |
|---|---|---|---|
A-101 | R Sharma | 4520 | 4608 |
A-102 | S Iyer | 3310 | 3585 |
B-201 | M Khan | 7788 | 8190 |
B-202 | D Rao | 1200 | 1850 |
6How it works, step by step
Each row gives previous and current readings; units used is the difference.
units_cost() walks the slabs in order, charging each block at its own rate until the units run out.
The fixed monthly charge is added to the slab cost.
Every flat's line is written to bills.txt in aligned columns.
7Source code
# ---------------------------------------------------------------------------
# electricity.py
#
# Slab-wise electricity bills for a housing society. Meter readings for every
# flat are read from a CSV file; a bill for each is written to a text file.
#
# A slab tariff does not charge every unit at the same rate: the first hundred
# units cost less than the next hundred, and so on. Getting that right is the
# whole of this program.
# ---------------------------------------------------------------------------
import csv
# The tariff, as (upper edge of the slab, rate per unit inside it).
# None means "everything above the previous edge", so the last entry has no
# upper limit. Keeping the tariff here means a revision by the board is one
# line to edit.
SLABS = [(100, 3.50), (200, 4.75), (400, 6.20), (None, 7.90)]
FIXED = 75.0 # fixed monthly charge, added to every bill
def units_cost(units):
"""Charge each slab at its own rate, the way a real tariff works."""
cost = 0 # money charged so far
used = 0 # units accounted for so far
for limit, rate in SLABS:
if limit is None:
# The last slab has no upper edge, so everything left falls in it.
block = units - used
else:
# Otherwise take whichever is smaller: what is left to charge, or
# what fits inside this slab. Without the min() a big reading would
# be charged for more units than were actually used.
block = min(units - used, limit - used)
if block <= 0:
break # nothing falls in this slab, so nothing above it
cost = cost + block * rate
used = used + block
if used >= units:
break # everything has been charged
return cost
def make_bills(reading_file, bill_file):
"""Read every flat's readings and write out a bill for each."""
# Both files are opened at once: one to read from, one to write to.
with open(reading_file, newline="") as f, open(bill_file, "w") as out:
out.write("LAMBDALAB RESIDENCY — ELECTRICITY BILLS\n\n")
out.write("{:<8}{:<16}{:>8}{:>12}\n".format("FLAT", "NAME", "UNITS", "AMOUNT"))
for row in csv.DictReader(f):
# Units used is the difference between the two readings. int() is
# needed because everything read from a file arrives as text.
units = int(row["current"]) - int(row["previous"])
amount = units_cost(units) + FIXED
out.write("{:<8}{:<16}{:>8}{:>12.2f}\n".format(
row["flat"], row["name"], units, amount))
# --- the program itself ----------------------------------------------------
make_bills("readings.csv", "bills.txt")
print(open("bills.txt").read()) # show the bills on screen as wellflat,name,previous,current
A-101,R Sharma,4520,4608
A-102,S Iyer,3310,3585
B-201,M Khan,7788,8190
B-202,D Rao,1200,1850The full report as a PDF — cover page, certificate, index, code, output, future scope and references, ready to print and fill in. Or the code on its own as a zip.
8Sample output
This is a real run, not a mock-up — the transcript below is what the program actually printed.
C:\LambdaLab\Projects\Electricity> python electricity.py
LAMBDALAB RESIDENCY — ELECTRICITY BILLS
FLAT NAME UNITS AMOUNT
A-101 R Sharma 88 383.00
A-102 S Iyer 275 1365.00
B-201 M Khan 402 2155.80
B-202 D Rao 650 4115.00Running it also wrote bills.txt. This is what that file held afterwards:
LAMBDALAB RESIDENCY — ELECTRICITY BILLS
FLAT NAME UNITS AMOUNT
A-101 R Sharma 88 383.00
A-102 S Iyer 275 1365.00
B-201 M Khan 402 2155.80
B-202 D Rao 650 4115.009Testing
Every case below was actually run and the result recorded as it appeared — including the ones expected to fail.
| Test case | Expected | Actual |
|---|---|---|
| Four flats across all four slabs | 650 units billed at Rs 4115.00 | B-202 D Rao 650 4115.00 |
| A flat that used nothing | Only the fixed charge, Rs 75.00 | A-1 Test 0 75.00 |
| Exactly 100 units, the first slab edge | 100 x 3.50 + 75 = Rs 425.00 | A-1 Test 100 425.00 |
| 101 units, one unit into the second slab | 425.00 + 4.75 = Rs 429.75 | A-1 Test 101 429.75 |
| readings.csv missing | FileNotFoundError | FileNotFoundError: [Errno 2] No such file or directory: 'readings.csv' |
Two kinds of case are in there on purpose. The boundary cases test the edge of a rule, where a program is most often wrong by one. The failure cases check that it refuses cleanly and says why, instead of quietly producing a wrong answer.
10Advantages
Set against the ways the job is done today:
- Every bill uses the same slab arithmetic, so none is wrong by accident
- A tariff revision is one edit rather than forty re-learnt calculations
- Readings are typed once and used for the whole society
- The bills are produced in a printable form, ready to distribute
- A resident's charge can be checked against the reading in seconds
11Future scope
What this version does not do
A report should be honest about its own limits, and each of these is the reason for one of the additions below:
- Arrears and previous balances are not carried forward
- A meter that has been replaced and restarted at zero would give a negative reading
- All flats are charged on the same tariff; commercial units are not separated
- Bills are written into one file rather than one page per flat
Proposed enhancements
This is also where you make the project yours. Pick one or two of these, or something nobody here thought of:
- Carry forward arrears and show the previous balance on the bill
- Print each bill on its own page ready to slip under a door
- Chart a flat's usage over twelve months so a leak or a faulty meter shows up
- Send the bill by email or WhatsApp instead of printing
- Handle a meter that has been replaced and restarted at zero
12What you may have to teach yourself
CBSE expects some self-learning in a project, and says so. For this one, that means:
- How your own electricity board's slabs actually work — read a real bill
- min() inside the slab loop, which is what stops a block over-counting
- Optional: how to lay out a bill for printing on A5
13Conclusion
Forty bills that took an evening and a calculator are now produced from one file of readings, with every slab charged at its own rate and no possibility of a slip.
Keeping the tariff in a single list, rather than spread through the code, means the program will survive the next revision by the board. That is worth more than any feature in it.
14References
Every report needs a bibliography. This one used:
- Computer Science with Python, Class XII — the NCERT / CBSE prescribed textbook, for the chapters on file handling and working with text and CSV files
- Computer Science with Python, Class XI — for functions, lists, dictionaries and string handling
- Python 3 documentation — https://docs.python.org/3/
- CBSE Senior School Curriculum, Computer Science (Subject Code 083) — the project guidelines this report follows
- LambdaLab — https://www.lambdalab.in