def process(self):
     now = datetime.now()
     try:
         vehicle_status = self.psacc.vehicles_list.get_car_by_vin(self.vin).get_status()
         status = vehicle_status.get_energy('Electric').charging.status
         level = vehicle_status.get_energy('Electric').level
         logger.info("charging status of %s is %s, battery level: %d", self.vin, status, level)
         if status == "InProgress":
             self.force_update()
             if level >= self.percentage_threshold and self.retry_count < 2:
                 logger.info("Charge threshold is reached, stop the charge")
                 self.control_charge_with_ack(False)
             elif self._next_stop_hour is not None:
                 if self._next_stop_hour < now:
                     self._next_stop_hour += timedelta(days=1)
                     logger.info("it's time to stop the charge")
                     self.control_charge_with_ack(False)
                 else:
                     next_in_second = (self._next_stop_hour - now).total_seconds()
                     if next_in_second < self.psacc.info_refresh_rate:
                         periodicity = next_in_second
                         thread = threading.Timer(periodicity, self.process)
                         thread.setDaemon(True)
                         thread.start()
         else:
             if self._next_stop_hour is not None and self._next_stop_hour < now:
                 self._next_stop_hour += timedelta(days=1)
             self.retry_count = 0
     except AttributeError:
         logger.error("Probably can't retrieve all information from API: %s", traceback.format_exc())
     except:
         logger.error(traceback.format_exc())
Beispiel #2
0
 def getStat(self, results):
     total = len(results)
     if total == 0:
         logger.error('No sample')
         return 0, 0, 0
     succ_results = [result for result in results if result['succ'] is True]
     total_succ = len(succ_results)
     latencies = [
         task_result['response_time'] - task_result['send_time']
         for task_result in succ_results if task_result['succ'] is True
     ]
     if len(latencies) == 0:
         logger.error('No succ sample')
         return 0, 0, 0
     avg_lat = sum(latencies) / len(latencies)
     wait_times = [
         task_result['send_time'] - task_result['create_time']
         for task_result in succ_results
     ]
     avg_wait_time = sum(wait_times) / len(wait_times)
     logger.debug('Succ rate: {} / {} = {}'.format(
         total_succ, total, 100.0 * total_succ / total))
     logger.debug('Avg latency: {}'.format(avg_lat))
     logger.debug('Avg wait time: {}'.format(avg_wait_time))
     return 100.0 * total_succ / total, 1000 * avg_lat, avg_wait_time
Beispiel #3
0
    def createTask(self, id, taskType):
        param = {}
        hostname = self.config.getHostname()
        char_candidates = string.digits
        short_id = ''.join(random.choice(char_candidates) for i in range(3))
        index_url = self.config.getIndexUrl()
        convert_url = self.config.getConvertUrl()
        short_id = str(short_id).rjust(6, '0')

        url_list = [
            'www.douban.com', 'www.baidu.com', 'www.google.com',
            'www.facebook.com'
        ]
        long_url = random.choice(url_list)

        if taskType == 'read':
            param = {
                "type": taskType,
                "hostname": hostname,
                "index_url": index_url,
                "short_id": short_id
            }
        elif taskType == 'write':
            param = {
                "type": taskType,
                "hostname": hostname,
                "index_url": index_url,
                "convert_url": convert_url,
                "long_url": long_url
            }
        else:
            logger.error('Unsupported task type {}'.format(taskType))

        return Task(id, param)
Beispiel #4
0
def update_trips():
    global trips, chargings, cached_layout
    logger.info("update_data")
    try:
        trips_by_vin = Trips.get_trips(myp.vehicles_list)
        trips = next(iter(trips_by_vin.values()))  # todo handle multiple car
        chargings = MyPSACC.get_chargings()
    except StopIteration:
        logger.debug("No trips yet")
        return
    except AssertionError:
        logger.error("update_trips: %s", traceback.format_exc())
    # update for slider
    global min_date, max_date, min_millis, max_millis, step, marks
    try:
        min_date = trips[0].start_at
        max_date = trips[-1].start_at
        min_millis = figures.unix_time_millis(min_date)
        max_millis = figures.unix_time_millis(max_date)
        step = (max_millis - min_millis) / 100
        marks = figures.get_marks_from_start_end(min_date, max_date)
        cached_layout = None  # force regenerate layout
    except (ValueError, IndexError):
        logger.error("update_trips (slider): %s", traceback.format_exc())
    return
Beispiel #5
0
    def record_position(self, vin, mileage, latitude, longitude, date, level,
                        level_fuel, moving):
        conn = get_db()
        if mileage == 0:  # fix a bug of the api
            logger.error("The api return a wrong mileage for %s : %f", vin,
                         mileage)
        else:
            if conn.execute("SELECT Timestamp from position where Timestamp=?",
                            (date, )).fetchone() is None:
                temp = get_temp(latitude, longitude, self.weather_api)
                if level_fuel == 0:  # fix fuel level not provided when car is off
                    try:
                        level_fuel = conn.execute(
                            "SELECT level_fuel FROM position WHERE level_fuel>0 AND VIN=? ORDER BY Timestamp DESC "
                            "LIMIT 1", (vin, )).fetchone()[0]
                        logger.info(
                            "level_fuel fixed with last real value %f for %s",
                            level_fuel, vin)
                    except TypeError:
                        level_fuel = None
                        logger.info("level_fuel unfixed for %s", vin)

                conn.execute(
                    "INSERT INTO position(Timestamp,VIN,longitude,latitude,mileage,level,level_fuel,moving,"
                    "temperature) VALUES(?,?,?,?,?,?,?,?,?)",
                    (date, vin, longitude, latitude, mileage, level,
                     level_fuel, moving, temp))

                conn.commit()
                logger.info("new position recorded for %s", vin)
                clean_position(conn)
            else:
                logger.debug("position already saved")
Beispiel #6
0
 def refresh_remote_token(self, force=False):
     if not force and self.remote_token_last_update is not None:
         last_update: datetime = self.remote_token_last_update
         if (datetime.now() - last_update).total_seconds() < MQTT_TOKEN_TTL:
             return
     self.manager._refresh_token()
     res = self.manager.post(remote_url + self.client_id,
                             json={
                                 "grant_type": "refresh_token",
                                 "refresh_token": self.remote_refresh_token
                             },
                             headers=self.headers)
     data = res.json()
     logger.debug(f"refresh_remote_token: {data}")
     if "access_token" in data:
         self.remote_access_token = data["access_token"]
         self.remote_refresh_token = data["refresh_token"]
         self.remote_token_last_update = datetime.now()
     else:
         logger.error(
             f"can't refresh_remote_token: {data}\n Create a new one")
         self.remote_token_last_update = datetime.now()
         otp_code = self.getOtpCode()
         res = self.get_remote_access_token(otp_code)
     self.mqtt_client.username_pw_set("IMA_OAUTH_ACCESS_TOKEN",
                                      self.remote_access_token)
     return res
Beispiel #7
0
def update_trips():
    global trips, chargings
    logger.info("update_data")
    try:
        trips = MyPSACC.get_trips()
        chargings = MyPSACC.get_chargings()
    except:
        logger.error("update_trips: " + traceback.format_exc())
Beispiel #8
0
 def on_mqtt_disconnect(self, client, userdata, rc):
     try:
         logger.warn("Disconnected with result code " + str(rc))
         # Subscribing in on_connect() means that if we lose the connection and
         # reconnect then subscriptions will be renewed.
         logger.warn(mqtt.error_string(rc))
     except:
         logger.error(traceback.format_exc())
Beispiel #9
0
 def on_mqtt_disconnect(self, client, userdata, rc):
     try:
         logger.warn("Disconnected with result code " + str(rc))
         if rc == 1:
             self.refresh_remote_token(force=True)
         else:
             logger.warn(mqtt.error_string(rc))
     except:
         logger.error(traceback.format_exc())
Beispiel #10
0
 def get_vehicles(self):
     try:
         res = self.api().get_vehicles_by_device()
         for vehicle in res.embedded.vehicles:
             self.vehicles_list.add(
                 Car(vehicle.vin, vehicle.id, vehicle.brand, vehicle.label))
         self.vehicles_list.save_cars()
     except ApiException:
         logger.error(traceback.format_exc())
     return self.vehicles_list
Beispiel #11
0
 def on_mqtt_disconnect(self, client, userdata, rc):
     try:
         logger.warn("Disconnected with result code " + str(rc))
         # Subscribing in on_connect() means that if we lose the connection and
         # reconnect then subscriptions will be renewed.
         logger.warn(mqtt.error_string(rc))
     except:
         logger.error(traceback.format_exc())
     self.mqtt_client.username_pw_set("IMA_OAUTH_ACCESS_TOKEN",
                                      self.remote_access_token)
Beispiel #12
0
 def on_mqtt_connect(self, client, userdata, rc, a):
     try:
         logger.info("Connected with result code " + str(rc))
         topics = [MQTT_RESP_TOPIC + self.customer_id + "/#"]
         for vin in self.getVIN():
             topics.append(MQTT_EVENT_TOPIC + vin)
         for topic in topics:
             client.subscribe(topic)
             logger.info("subscribe to " + topic)
     except:
         logger.error(traceback.format_exc())
Beispiel #13
0
 def on_mqtt_connect(self, client, userdata, rc, a):
     try:
         logger.info("Connected with result code " + str(rc))
         topics = ["psa/RemoteServices/to/cid/" + self.customer_id + "/#"]
         for vin in self.getVIN():
             topics.append("psa/RemoteServices/events/MPHRTServices/" +
                           vin + "/#")
         for topic in topics:
             client.subscribe(topic)
             logger.info("subscribe to " + topic)
     except:
         logger.error(traceback.format_exc())
Beispiel #14
0
 def on_mqtt_message(self, client, userdata, msg):
     logger.info(f"mqtt msg {msg.topic} {str(msg.payload)}")
     try:
         data = json.loads(msg.payload)
         if data["return_code"] == "0":
             return
         elif data["return_code"] == "400":
             self.manager._refresh_token()
             self.refresh_remote_token()
             logger.info("retry last request")
         else:
             logger.error(f'{data["return_code"]} : {data["reason"]}')
     except:
         logger.debug("mqtt msg hasn't return code")
Beispiel #15
0
 def on_mqtt_message(self, client, userdata, msg):
     try:
         logger.info("mqtt msg %s %s", msg.topic, msg.payload)
         data = json.loads(msg.payload)
         charge_info = None
         if msg.topic.startswith(MQTT_RESP_TOPIC):
             if "return_code" not in data:
                 logger.debug("mqtt msg hasn't return code")
             elif data["return_code"] == "400":
                 self.refresh_remote_token(force=True)
                 logger.error("retry last request, token was expired")
             elif data["return_code"] == "300":
                 logger.error('%d', data["return_code"])
             elif data["return_code"] != "0":
                 logger.error('%s : %s', data["return_code"],
                              data["reason"])
                 if msg.topic.endswith("/VehicleState"):
                     charge_info = data["resp_data"]["charging_state"]
                     self.precond_programs[data["vin"]] = data["resp_data"][
                         "precond_state"]["programs"]
         elif msg.topic.startswith(MQTT_EVENT_TOPIC):
             charge_info = data["charging_state"]
         if charge_info is not None and charge_info[
                 'remaining_time'] != 0 and charge_info['rate'] == 0:
             # fix a psa server bug where charge beginning without status api being properly updated
             logger.warning("charge begin but API isn't updated")
             sleep(60)
             self.wakeup(data["vin"])
     except KeyError:
         logger.error(traceback.format_exc())
Beispiel #16
0
 def get_co2_per_kw(start: datetime, end: datetime, latitude, longitude):
     try:
         location = reverse_geocode.search([(latitude, longitude)])[0]
         country_code = location["country_code"]
     except UnicodeDecodeError:
         logger.error("Can't find country for %s %s", latitude, longitude)
         country_code = None
     except IndexError:
         country_code = None
     # todo implement other countries
     if country_code == 'FR':
         co2_per_kw = Ecomix.get_data_france(start, end)
     else:
         co2_per_kw = None
     return co2_per_kw
Beispiel #17
0
 def get_charge_hour(self, vin):
     reg = r"PT([0-9]{1,2})H([0-9]{1,2})?"
     data = self.get_vehicle_info(vin)
     hour_str = data.energy[0].charging.next_delayed_time
     try:
         hour = re.findall(reg, hour_str)[0]
         h = int(hour[0])
         if hour[1] == '':
             m = 0
         else:
             m = hour[1]
         return h, m
     except IndexError:
         logger.error(traceback.format_exc())
         logger.error(f"Can't get charge hour: {hour_str}")
Beispiel #18
0
 def get_vehicle_info(self, vin):
     res = None
     car = self.vehicles_list.get_car_by_vin(vin)
     for _ in range(0, 2):
         try:
             res = self.api().get_vehicle_status(car.vehicle_id,
                                                 extension=["odometer"])
             if res is not None:
                 if self._record_enabled:
                     self.record_info(vin, res)
                 break
         except ApiException:
             logger.error(traceback.format_exc())
     car.status = res
     return res
Beispiel #19
0
def get_temp(latitude: str, longitude: str, api_key: str) -> float:
    try:
        if not (latitude is None or longitude is None or api_key is None):
            weather_rep = requests.get("https://api.openweathermap.org/data/2.5/onecall",
                                       params={"lat": latitude, "lon": longitude,
                                               "exclude": "minutely,hourly,daily,alerts",
                                               "appid": api_key,
                                               "units": "metric"})
            temp = weather_rep.json()["current"]["temp"]
            logger.debug("Temperature :%fc", temp)
            return temp
    except ConnectionError:
        logger.error("Can't connect to openweathermap :%s", traceback.format_exc())
    except KeyError:
        logger.error("Unable to get temperature from openweathermap :%s", traceback.format_exc())
    return None
Beispiel #20
0
    def start(self):
        periodicity = ChargeControl.periodicity
        now = datetime.now()
        if self._next_stop_hour is not None and self._next_stop_hour < now:
            stop_charge = True
            self._next_stop_hour += timedelta(days=1)
            logger.info("it's time to stop the charge")
        else:
            stop_charge = False

        if self.percentage_threshold != 100 or stop_charge:
            res = None
            try:
                res = self.psacc.get_vehicle_info(self.vin)
            except ApiException:
                logger.error(traceback.format_exc())
            if res is not None:
                status = res.energy[0]['charging']['status']
                level = res.energy[0]["level"]
                logger.info(
                    f"charging status of {self.vin} is {status}, battery level: {level}"
                )
                if status == "InProgress":
                    if (level >= self.percentage_threshold
                            and self.retry_count < 2) or stop_charge:
                        self.psacc.charge_now(self.vin, False)
                        self.retry_count += 1
                        sleep(ChargeControl.MQTT_TIMEOUT)
                        res = self.psacc.get_vehicle_info(self.vin)
                        status = res.energy[0]['charging']['status']
                        if status == "InProgress":
                            logger.warn(
                                f"retry to stop the charge of {self.vin}")
                            self.psacc.charge_now(self.vin, False)
                            self.retry_count += 1
                    if self._next_stop_hour is not None:
                        next_in_second = (self._next_stop_hour -
                                          now).total_seconds()
                        if next_in_second < periodicity:
                            periodicity = next_in_second
                else:
                    self.retry_count = 0
            else:
                logger.error(f"error when get vehicle info of {self.vin}")
        self.thread = threading.Timer(periodicity, self.start)
        self.thread.start()
Beispiel #21
0
 def refresh_remote_token(self, force=False):
     if not force and self.remote_token_last_update is not None:
         last_update: datetime = self.remote_token_last_update
         if (datetime.now() - last_update).total_seconds() < MQTT_TOKEN_TTL:
             return
     self.manager._refresh_token()
     res = self.manager.post(remote_url + self.client_id,
                             json={
                                 "grant_type": "refresh_token",
                                 "refresh_token": self.remote_refresh_token
                             },
                             headers=self.headers)
     data = res.json()
     logger.debug(f"refresh_remote_token: {data}")
     if "access_token" in data:
         self.remote_access_token = data["access_token"]
         self.remote_refresh_token = data["refresh_token"]
         self.remote_token_last_update = datetime.now()
         return data["access_token"], data["refresh_token"]
     else:
         logger.error(f"can't refresh_remote_token: {data}")
Beispiel #22
0
    def execute(self):
        logger.info('Running task: {}'.format(self.id))
        self.send_time = time.time()
        if self.param['type'] == 'read':
            result = self.readTask()
        elif self.param['type'] == 'write':
            result = self.writeTask()
        else:
            logger.error('Unsupported task type {}'.format(self.param['type']))
        self.response_time = time.time()

        Stat.finished_tasks += 1
        task_stat = {
            'id': self.id,
            'type': self.param['type'],
            'create_time': self.create_time,
            'send_time': self.send_time,
            'response_time': self.response_time,
            'succ': result['succ'],
        }
        Stat.result_queue.put(task_stat)
Beispiel #23
0
 def record_info(self, vin, status: psac.models.status.Status):
     mileage = status.timed_odometer.mileage
     level = status.get_energy('Electric').level
     level_fuel = status.get_energy('Fuel').level
     charge_date = status.get_energy('Electric').updated_at
     try:
         moving = status.kinetic.moving
         logger.debug("")
     except AttributeError:
         logger.error("kinetic not available from api")
         moving = None
     try:
         longitude = status.last_position.geometry.coordinates[0]
         latitude = status.last_position.geometry.coordinates[1]
         date = status.last_position.properties.updated_at
     except AttributeError:
         logger.error("last_position not available from api")
         longitude = latitude = None
         date = charge_date
     logger.debug(
         "vin:%s longitude:%s latitude:%s date:%s mileage:%s level:%s charge_date:%s level_fuel:"
         "%s moving:%s", vin, longitude, latitude, date, mileage, level,
         charge_date, level_fuel, moving)
     self.record_position(vin, mileage, latitude, longitude, date, level,
                          level_fuel, moving)
     try:
         charging_status = status.get_energy('Electric').charging.status
         self.record_charging(vin, charging_status, charge_date, level,
                              latitude, longitude)
         logger.debug("charging_status:%s ", charging_status)
     except AttributeError:
         logger.error("charging status not available from api")
Beispiel #24
0
 def on_mqtt_message(self, client, userdata, msg):
     charge_not_detected = False
     try:
         logger.info(f"mqtt msg {msg.topic} {str(msg.payload)}")
         data = json.loads(msg.payload)
         if msg.topic.startswith(MQTT_RESP_TOPIC):
             if "return_code" in data:
                 if data["return_code"] == "0":
                     pass
                 elif data["return_code"] == "400":
                     self.refresh_remote_token(force=True)
                     logger.error("retry last request, token was expired")
                 else:
                     logger.error(
                         f'{data["return_code"]} : {data["reason"]}')
             else:
                 logger.debug("mqtt msg hasn't return code")
         if msg.topic.startswith(MQTT_EVENT_TOPIC):
             if data["charging_state"]['remaining_time'] != 0 and data[
                     "charging_state"]['rate'] == 0:
                 charge_not_detected = True
         elif msg.topic.endswith("/VehicleState"):
             if data["resp_data"]["charging_state"]['remaining_time'] != 0 \
                     and data["resp_data"]["charging_state"]['rate'] == 0:
                 charge_not_detected = True
         if charge_not_detected:
             # fix a psa server bug where charge beginning without status api being properly updated
             logger.info("charge begin")
             sleep(60)
             self.wakeup(data["vin"])
     except:
         logger.error(traceback.format_exc())
Beispiel #25
0
 def on_mqtt_message(self, client, userdata, msg):
     try:
         logger.info(f"mqtt msg {msg.topic} {str(msg.payload)}")
         data = json.loads(msg.payload)
         if msg.topic.startswith(MQTT_RESP_TOPIC):
             if "return_code" in data:
                 if data["return_code"] == "0":
                     return
                 elif data["return_code"] == "400":
                     self.refresh_remote_token(force=True)
                     logger.error("retry last request, token was expired")
                 else:
                     logger.error(
                         f'{data["return_code"]} : {data["reason"]}')
             else:
                 logger.debug("mqtt msg hasn't return code")
         elif msg.topic.startswith(MQTT_EVENT_TOPIC):
             # fix charge beginning without status api being updated
             if data["charging_state"]['remaining_time'] != 0 and data[
                     "charging_state"]['rate'] == 0:
                 logger.info("charge begin")
                 sleep(60)
                 self.wakeup(data["vin"])
     except:
         logger.error(traceback.format_exc())
Beispiel #26
0
    def start(self):
        periodicity = ChargeControl.periodicity
        now = datetime.now()
        try:
            if self._next_stop_hour is not None and self._next_stop_hour < now:
                stop_charge = True
                self._next_stop_hour += timedelta(days=1)
                logger.info("it's time to stop the charge")
            else:
                stop_charge = False

            if self.percentage_threshold != 100 or stop_charge or self.always_check:
                res = None
                try:
                    res = self.psacc.get_vehicle_info(self.vin)
                except ApiException:
                    logger.error(traceback.format_exc())
                if res is not None:
                    status = res.energy[0].charging.status
                    level = res.energy[0].level
                    logger.info(
                        f"charging status of {self.vin} is {status}, battery level: {level}"
                    )
                    if status == "InProgress":
                        # force update if the car doesn't send info during 10 minutes
                        last_update = res.energy[0].updated_at
                        if (datetime.utcnow().replace(tzinfo=pytz.UTC) -
                                last_update).total_seconds() > 60 * 10:
                            self.psacc.wakeup(self.vin)
                        if (level >= self.percentage_threshold
                                and self.retry_count < 2) or stop_charge:
                            self.psacc.charge_now(self.vin, False)
                            self.retry_count += 1
                            sleep(ChargeControl.MQTT_TIMEOUT)
                            res = self.psacc.get_vehicle_info(self.vin)
                            status = res.energy[0].charging.status
                            if status == "InProgress":
                                logger.warn(
                                    f"retry to stop the charge of {self.vin}")
                                self.psacc.charge_now(self.vin, False)
                                self.retry_count += 1
                        if self._next_stop_hour is not None:
                            next_in_second = (self._next_stop_hour -
                                              now).total_seconds()
                            if next_in_second < periodicity:
                                periodicity = next_in_second
                    else:
                        self.retry_count = 0
                else:
                    logger.error(f"error when get vehicle info of {self.vin}")
        except:
            logger.error(traceback.format_exc())
        self.thread = threading.Timer(periodicity, self.start)
        self.thread.start()
Beispiel #27
0
 def get_status(self):
     if self.status is not None:
         return self.status
     logger.error("status of %s is None", self.vin)
     raise ValueError("status of %s is None")
Beispiel #28
0
                            tab_id="battery",
                            id="tab_battery",
                            children=[figures.battery_info]),
                    dbc.Tab(label="Map",
                            tab_id="map",
                            children=[
                                dcc.Graph(figure=figures.trips_map,
                                          id="trips_map",
                                          style={"height": '90vh'})
                            ]),
                ],
                id="tabs",
                active_tab="summary",
            ),
            html.Div(id="tab-content", className="p-4"),
        ])
    ])
except (IndexError, TypeError) as e:
    logger.debug(
        "Failed to generate figure, there is probably not enough data yet")
    data_div = dbc.Alert("No data to show", color="danger")

except:
    logger.error(
        "Failed to generate figure, there is probably not enough data yet")
    logger.error(traceback.format_exc())
    data_div = dbc.Alert("No data to show", color="danger")

dash_app.layout = dbc.Container(fluid=True,
                                children=[html.H1('My car info'), data_div])
Beispiel #29
0
    def record_info(self, vin, status: psac.models.status.Status):
        longitude = status.last_position.geometry.coordinates[0]
        latitude = status.last_position.geometry.coordinates[1]
        date = status.last_position.properties.updated_at
        mileage = status.timed_odometer.mileage
        level = status.energy[0].level
        charging_status = status.energy[0].charging.status
        moving = status.kinetic.moving
        conn = get_db()
        if mileage == 0:  # fix a bug of the api
            logger.error(
                f"The api return a wrong mileage for {vin} : {mileage}")
        else:
            if conn.execute("SELECT Timestamp from position where Timestamp=?",
                            (date, )).fetchone() is None:
                temp = None
                if self.weather_api is not None:
                    try:
                        weather_rep = requests.get(
                            "https://api.openweathermap.org/data/2.5/onecall",
                            params={
                                "lat": latitude,
                                "lon": longitude,
                                "exclude": "minutely,hourly,daily,alerts",
                                "appid": "f8ee4124ea074950b696fd3e956a7069",
                                "units": "metric"
                            })
                        temp = weather_rep.json()["current"]["temp"]
                        logger.debug(f"Temperature :{temp}c")
                    except Exception as e:
                        logger.error(
                            f"Unable to get temperature from openweathermap :{e}"
                        )

                conn.execute(
                    "INSERT INTO position(Timestamp,VIN,longitude,latitude,mileage,level, moving, temperature) VALUES(?,?,?,?,?,?,?,?)",
                    (date, vin, longitude, latitude, mileage, level, moving,
                     temp))

                conn.commit()
                logger.info(f"new position recorded for {vin}")
                res = conn.execute(
                    "SELECT Timestamp,mileage,level from position ORDER BY Timestamp DESC LIMIT 3;"
                ).fetchall()
                # Clean DB
                if len(res) == 3:
                    if res[0]["mileage"] == res[1]["mileage"] == res[2][
                            "mileage"]:
                        if res[0]["level"] == res[1]["level"] == res[2][
                                "level"]:
                            logger.debug("Delete duplicate line")
                            conn.execute(
                                "DELETE FROM position where Timestamp=?;",
                                (res[1]["Timestamp"], ))
                            conn.commit()
            else:
                logger.debug("position already saved")

        # todo handle battery status
        charge_date = status.energy[0].updated_at
        if charging_status == "InProgress":
            try:
                in_progress = conn.execute(
                    "SELECT stop_at FROM battery WHERE VIN=? ORDER BY start_at DESC limit 1",
                    (vin, )).fetchone()[0] is None
            except TypeError:
                in_progress = False
            if not in_progress:
                res = conn.execute(
                    "INSERT INTO battery(start_at,start_level,VIN) VALUES(?,?,?)",
                    (charge_date, level, vin))
                conn.commit()
        else:
            try:
                start_at, stop_at, start_level = conn.execute(
                    "SELECT start_at, stop_at, start_level from battery WHERE VIN=? ORDER BY start_at "
                    "DESC limit 1", (vin, )).fetchone()
                in_progress = stop_at is None
                if in_progress:
                    co2_per_kw = Ecomix.get_co2_per_kw(start_at, charge_date,
                                                       latitude, longitude)
                    kw = (level - start_level) / 100 * BATTERY_POWER
                    res = conn.execute(
                        "UPDATE battery set stop_at=?, end_level=?, co2=?, kw=? WHERE start_at=? and VIN=?",
                        (charge_date, level, co2_per_kw, kw, start_at, vin))
                    conn.commit()
            except TypeError:
                logger.debug("battery table is empty")
            except:
                logger.debug("Error when saving status " +
                             traceback.format_exc())
        conn.close()
Beispiel #30
0
    def activation_finalyze(self, random_bytes=None):

        R = self.get_r()
        params = {
            "action": "ActionFinalize",
            "mode": self.mode,
            "id": self.data.iwid,
            "lastsync": self.data.iwTsync,
            "version": "Generator-1.0/0.2.11",
            "lang": "fr",
            "ack": "",
            "macid": self.macid
        }
        if self.mode == Otp.OTP_MODE:
            params.update({"keytype": '0', "sid": self.data.iwsecid})

        elif self.mode == Otp.ACTIVATE_MODE:
            kma_crypt = self.cipher.encrypt(
                bytes.fromhex(self.generate_kma(self.codepin))).hex()
            pin_crypt = self.cipher.encrypt(self.codepin.encode("utf-8")).hex()
            params.update({
                "serial": self.get_serial(),
                "code": self.smsCode,
                "Kma": kma_crypt,
                "pin": pin_crypt,
                "name": "Android SDK built for x86_64 / UNKNOWN",
            })

        params.update(R)
        xml = self.request(params)
        if xml["err"] != "OK":
            logger.error("Error during activation: %s", xml)
            return Otp.NOK
        self.data.synchro(xml, self.generate_kma(self.codepin))

        if self.mode == Otp.OTP_MODE:
            try:
                self.defi = str(xml["defi"])
            except KeyError:
                raise ConfigException
            if "J" in xml:
                logger.debug("Need another otp request")
                return Otp.OTP_TWICE
            return Otp.OK

        if "ms_n" not in xml or xml["ms_n"] == 0:
            logger.debug("no ms_n request needed")
            return Otp.OK

        if int(xml["ms_n"]) > 1:
            raise NotImplementedError
        ms_n = "0"

        self.challenge = xml["challenge"]
        self.action = "synchro"
        res = self.decode_oaep(xml["ms_key"], self.Kfact)
        temp_key = RSA.construct((int(res, 16), self.exponent))
        temp_cipher = oaep.new(temp_key, hash_algo=Hash.SHA256)
        if random_bytes is None:
            random_bytes = token_bytes(16)
        kpub_encode = temp_cipher.encrypt(random_bytes)

        aes_cipher = AES.new(bytes.fromhex(self.generate_kma(self.codepin)),
                             AES.MODE_ECB)
        encode_aes_from_hex = aes_cipher.encrypt(random_bytes).hex()
        self.data.iwsecval = encode_aes_from_hex
        self.data.iwsecid = xml["s_id"]
        self.data.iwsecn = 1

        req_param = {
            "action": "ActionFinalize",
            "mode": Otp.MS_MODE,
            "ms_id" + ms_n: xml["ms_id"],
            "ms_val" + ms_n: kpub_encode.hex(),
            "macid": self.macid
        }
        req_param.update({
            "id": self.data.iwid,
            "lastsync": self.data.iwTsync,
            "ms_n": 1
        })
        req_param.update(self.get_r())
        xml = self.request(req_param)
        self.data.synchro(xml, self.generate_kma(self.codepin))
        return Otp.OK