From 0f78abded8dc726d9ecd1eadf1179d0947196096 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Mon, 29 Mar 2021 11:54:14 +0200 Subject: [PATCH] Release 1.0.0 --- .gitignore | 2 + classes/Build.py | 75 ++++++++++++++++++++++ classes/Functions.py | 15 +++-- classes/Import.py | 3 +- classes/Merge.py | 28 +++++--- classes/Vehicle.py | 34 ++++++++++ classes/__init__.py | 6 +- classes/settings.py | 8 --- public/{vehicles.php => vehicles.json.php} | 2 +- run.py | 42 +++++++++++- 10 files changed, 184 insertions(+), 31 deletions(-) create mode 100644 classes/Build.py create mode 100644 classes/Vehicle.py delete mode 100644 classes/settings.py rename public/{vehicles.php => vehicles.json.php} (87%) diff --git a/.gitignore b/.gitignore index 0346efa..148fd4e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ +__pycache__ + data/* !.placeholder \ No newline at end of file diff --git a/classes/Build.py b/classes/Build.py new file mode 100644 index 0000000..e9da584 --- /dev/null +++ b/classes/Build.py @@ -0,0 +1,75 @@ +import json + +from .Vehicle import VehicleData + +# Create an echarge-configurator compatible list +class EchargeConfiguratorList: + def __init__(self): + self.output = {} + + # -- Create lists -- + + def add_make(self,make): + if make not in self.output: + self.output[make] = {} + + def add_model(self,make,model): + if make not in self.output[make]: + self.output[make][model] = {} + + def add_year(self,make,model,year): + if year not in self.output[make][model]: + self.output[make][model][year] = {} + + # ---- + + def add(self,make,model,year): + self.add_make(make) + self.add_model(make,model) + self.add_year(make,model,year) + + return self.output[make][model][year] + + # Save built output to file + def write(self,dest): + with open(dest,"w") as f: + json.dump(self.output,f) + return True + +# Process data from vehicles_stored.json and cables.json +class Build(EchargeConfiguratorList): + def __init__(self,vehicles,cables): + super(Build,self).__init__() + self.input = vehicles + self.cables = cables + + self.worker(cables) + + def add_details(self,vehicle): + data = { + "ob_charger": { + "plug": vehicle.data["Charge_Plug"], + "power": str(vehicle.data["Charge_Standard_Power"]), + "phase": str(vehicle.data["Charge_Standard_Phase"]), + "charge_time": str(vehicle.data["Charge_Standard_ChargeTime"]) + } + } + + return data + + def add_cables(self,vehicle): + data = vehicle.compatibility(self.cables) + return data + + def worker(self,cables): + for i in self.input: + vehicle = VehicleData(self.input[i]) + if(not vehicle.valid): + continue + + output = self.add(vehicle.data["Vehicle_Make"],vehicle.data["Vehicle_Model"],vehicle.data["Availability_Date_From"][3:]) + + # Append vehicle data + output["details"] = self.add_details(vehicle) + output["cables"] = self.add_cables(vehicle) + \ No newline at end of file diff --git a/classes/Functions.py b/classes/Functions.py index e1e1111..20d5658 100644 --- a/classes/Functions.py +++ b/classes/Functions.py @@ -1,12 +1,15 @@ import json from pathlib import Path -# Import a JSON file -def load_JSON(f): +# Attempt to load JSON into memory +def load(self,f): if not Path(f).is_file(): - return False - + raise IOError(f"Input file '{x}' not found") + with open(f) as f: - data = json.load(f) + return json.load(f) - return data \ No newline at end of file +# Map key,value list +def forEach(list,func): + for i,v in enumerate(list): + func(v,i,list) \ No newline at end of file diff --git a/classes/Import.py b/classes/Import.py index e7ede35..7c5ecdc 100644 --- a/classes/Import.py +++ b/classes/Import.py @@ -8,7 +8,7 @@ class File: def fetch(): http = httplib2.Http() - response, content = http.request(File.endpoint, "GET") + response, content = http.request(File.endpoint,"GET") handle = open(File.dataPath,"w") handle.write(content.decode("utf-8")) @@ -44,6 +44,7 @@ def validVehicle(vehicle): return True + # Return compatible cables based on type, ampere and phase def compatibleCables(type,ampere,phase): # Type 1 if(type == "Type 1"): diff --git a/classes/Merge.py b/classes/Merge.py index 70afbab..92562ba 100644 --- a/classes/Merge.py +++ b/classes/Merge.py @@ -1,14 +1,24 @@ import json -from .Functions import * -from .settings import * - -# Merge insert two objects +# Merge new vehicle data with existing vehicle data class Merge: + def __init__(self,data_from,data_to): + self.input = self.assigned_list(data_from) # Merge this.. + self.output = data_to # ..With this + + # Merge lists + self.output.update(self.input) - def __init__(self,this,that): - self.data_target = load_JSON(data_vehicles) - self.data_insert = load_JSON(data_vehicles_new) + # Create assigned list from EVDB array of objects + def assigned_list(self,data): + output = {} + for vehicle in data: + key = str(vehicle["Vehicle_ID"]) + output[key] = vehicle + return output - def run(self): - print(data_vehicles_new) \ No newline at end of file + # Save merged output to file + def write(self,dest): + with open(dest,"w") as f: + json.dump(self.output,f) + return True \ No newline at end of file diff --git a/classes/Vehicle.py b/classes/Vehicle.py new file mode 100644 index 0000000..975d94e --- /dev/null +++ b/classes/Vehicle.py @@ -0,0 +1,34 @@ +class VehicleData: + def __init__(self,data): + self.valid = True + self.data = data + + if(data["Availability_Status"] > 1): + self.valid = False + + # Return compatible cables ordered by best-fit + def compatibility(self,cables): + plug = self.data["Charge_Plug"] + phase = self.data["Charge_Standard_Phase"] + ampere = self.data["Charge_Standard_PhaseAmp"] + + output = [] + + # -- Best-fit hierarchy -- + + # Plug; Type 1 + if(plug == "Type 1"): + output = cables["Type 1"]["1-Phase"]["16A"] + return output + + # Plug; Type 2 + if(phase > 1): + if(ampere > 16): + output = cables["Type 2"]["3-Phase"]["32A"] + output + output = output + cables["Type 2"]["3-Phase"]["16A"] + + if(ampere > 16): + output = output + cables["Type 2"]["1-Phase"]["32A"] + output = output + cables["Type 2"]["1-Phase"]["16A"] + + return output \ No newline at end of file diff --git a/classes/__init__.py b/classes/__init__.py index b47c951..a42df0f 100644 --- a/classes/__init__.py +++ b/classes/__init__.py @@ -1,4 +1,2 @@ -from .settings import * - -from .Functions import * -from .Merge import * \ No newline at end of file +from .Merge import Merge +from .Build import Build \ No newline at end of file diff --git a/classes/settings.py b/classes/settings.py deleted file mode 100644 index 2341bc7..0000000 --- a/classes/settings.py +++ /dev/null @@ -1,8 +0,0 @@ -# Global variables. Add vairables here to make them available to all -# classes under the "config" alias. (config.data_vehicles) -import os - -endpoint = os.environ.get("ECHARGE_CONFIGURATOR_ENDPOINT") - -data_vehicles = "data/vehicles.json" -data_vehicles_new = "data/new_vehicles.json" \ No newline at end of file diff --git a/public/vehicles.php b/public/vehicles.json.php similarity index 87% rename from public/vehicles.php rename to public/vehicles.json.php index 6d949fb..fb96a80 100644 --- a/public/vehicles.php +++ b/public/vehicles.json.php @@ -10,6 +10,6 @@ ]; } - echo json_encode($output); + echo $output; ?> \ No newline at end of file diff --git a/run.py b/run.py index bf87d17..f06d980 100644 --- a/run.py +++ b/run.py @@ -1,4 +1,42 @@ +import os +import json +from shutil import copyfile +from pathlib import Path + import classes -merge = classes.Merge() -merge.run() \ No newline at end of file +# Fetch raw data from this endpoint +endpoint = os.environ.get("ECHARGE_CONFIGURATOR_ENDPOINT") + +files = { + "vehicles_processed": "data/vehicles.json", + "vehicles_stored": "data/vehicles_stored.json", + "vehicles_new": "data/vehicles_new.json", + "cables": "cables.json" +} + +# Load JSON into memory +def load_json(f): + if not Path(f).is_file(): + raise IOError(f"Input file '{x}' not found") + + with open(f) as f: + return json.load(f) + +def backup(f): + try: + copyfile(f,f"{f}.backup") + except IOError as error: + print(error) + +# Clone existing vehicle archives before processing +backup(files["vehicles_processed"]) +backup(files["vehicles_stored"]) + +# Merge new vehicle data with stored vehicle data +merge = classes.Merge(load_json(files["vehicles_new"]),load_json(files["vehicles_stored"])) +merge.write(files["vehicles_stored"]) # Overwrite archive with new data + +# Create echarge-configurator compatible JSON from vehicle and cable data +process = classes.Build(merge.output,load_json(files["cables"])) +process.write(files["vehicles_processed"]) \ No newline at end of file