diff --git a/.idea/Model.iml b/.idea/Model.iml
index 4413bb06..b0f9c00d 100644
--- a/.idea/Model.iml
+++ b/.idea/Model.iml
@@ -7,7 +7,7 @@
-
+
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 6f308057..1122b380 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/backend/tests/test_annual_bill_savings.py b/backend/tests/test_annual_bill_savings.py
new file mode 100644
index 00000000..81c2898c
--- /dev/null
+++ b/backend/tests/test_annual_bill_savings.py
@@ -0,0 +1,82 @@
+import numpy as np
+import pytest
+from backend.ml_models.AnnualBillSavings import AnnualBillSavings
+
+appliance_consumption_cases = [
+ {
+ "total_floor_area": 13.9,
+ "n_occupants": 1,
+ "consumption": 718.4795859263703
+ },
+ {
+ "total_floor_area": 20,
+ "n_occupants": 1.0306381042556767,
+ "consumption": 865.2316409517844
+ },
+ {
+ "total_floor_area": 30,
+ "n_occupants": 1.1731577598127325,
+ "consumption": 1113.5965321501362
+ },
+ {
+ "total_floor_area": 50,
+ "n_occupants": 1.6901008890848956,
+ "consumption": 1683.31305074609
+ },
+ {
+ "total_floor_area": 75,
+ "n_occupants": 2.361158387531988,
+ "consumption": 2386.2935599981865
+ },
+ {
+ "total_floor_area": 100,
+ "n_occupants": 2.739525875076067,
+ "consumption": 2931.6076153011486
+ },
+ {
+ "total_floor_area": 125,
+ "n_occupants": 2.8807344137165405,
+ "consumption": 3335.143110751552
+ },
+ {
+ "total_floor_area": 150,
+ "n_occupants": 2.934188599837662,
+ "consumption": 3666.3228057866513
+ },
+ {
+ "total_floor_area": 200,
+ "n_occupants": 3.001920087128373,
+ "consumption": 4244.625403339813
+ },
+ {
+ "total_floor_area": 300,
+ "n_occupants": 3.1319299999993095,
+ "consumption": 5243.086106676302
+ },
+ {
+ "total_floor_area": 500,
+ "n_occupants": 3.39193,
+ "consumption": 6927.400500420533
+ },
+ {
+ "total_floor_area": 1000,
+ "n_occupants": 4.04193,
+ "consumption": 10434.755635642652
+ }
+]
+
+
+class TestAnnualBillSavings:
+
+ @pytest.mark.parametrize(
+ "test_case",
+ appliance_consumption_cases
+ )
+ def test_appliance_estimation(self, test_case):
+ n_occupants = AnnualBillSavings.calculate_occupants(test_case["total_floor_area"])
+ assert np.isclose(n_occupants, test_case["n_occupants"])
+
+ appliance_consumption = AnnualBillSavings.estimate_electrical_appliances(
+ n_occupants, test_case["total_floor_area"]
+ )
+ assert np.isclose(appliance_consumption, test_case["consumption"])
diff --git a/etl/customers/vander_elliot/non_intrusives.py b/etl/customers/vander_elliot/non_intrusives.py
new file mode 100644
index 00000000..e11bc3f8
--- /dev/null
+++ b/etl/customers/vander_elliot/non_intrusives.py
@@ -0,0 +1,17 @@
+from etl.non_intrusive_surveys.upload.UploadNonIntrusives import UploadNonIntrusives
+
+
+def app():
+ """
+ This script handles the creation of the portfolio for the non-intrusive surveys
+ :return:
+ """
+
+ non_intrusive_s3_filename = (
+ "customers/Vander Elliot/Non-intrusive survey template V2 - Amazon Management Services.xlsx"
+ )
+
+ non_intrusive = UploadNonIntrusives(
+ s3_template_location=non_intrusive_s3_filename,
+ s3_bucket="retrofit-datalake-dev",
+ )
diff --git a/etl/non_intrusive_surveys/photos/README.md b/etl/non_intrusive_surveys/photos/README.md
index 9dbe951f..a58603b4 100644
--- a/etl/non_intrusive_surveys/photos/README.md
+++ b/etl/non_intrusive_surveys/photos/README.md
@@ -15,5 +15,5 @@ pip install -r requirements.txt
The main application is found in the app.py file. To run the application, use the following command:
```bash
-python app.py
+python UploadNonIntrusives.py
```
\ No newline at end of file
diff --git a/etl/non_intrusive_surveys/upload/UploadNonIntrusives.py b/etl/non_intrusive_surveys/upload/UploadNonIntrusives.py
new file mode 100644
index 00000000..00f707e9
--- /dev/null
+++ b/etl/non_intrusive_surveys/upload/UploadNonIntrusives.py
@@ -0,0 +1,18 @@
+from utils.s3 import read_excel_from_s3
+
+
+class UploadNonIntrusives:
+ """
+ This class handles the upload of findings from the non-intrusive surveys, to the database
+ """
+
+ def __init__(self, s3_template_location, s3_bucket):
+ self.s3_template_location = s3_template_location
+ self.s3_bucket = s3_bucket
+ self.template = self.read_template()
+
+ def read_template(self):
+ """
+ This method reads the template from S3
+ """
+ return read_excel_from_s3(file_key=self.s3_template_location, bucket_name=self.s3_bucket, header_row=0)
diff --git a/etl/non_intrusive_surveys/upload/__init__.py b/etl/non_intrusive_surveys/upload/__init__.py
new file mode 100644
index 00000000..e69de29b