diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17578fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +.vscode +mainwindow.py \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e44208e --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Libelium Calibration App + +## Run +```bash +pyuic5 app/gui/mainwindow.ui -o app/gui/mainwindow.py +python3 app/libelium-calibration.py +``` \ No newline at end of file diff --git a/app/boards.py b/app/boards.py new file mode 100644 index 0000000..874b960 --- /dev/null +++ b/app/boards.py @@ -0,0 +1,183 @@ +import typing as tp + +from sensors import ( + ClSensor, + ConductivitySensor, + NH4Sensor, + NO2Sensor, + NO3Sensor, + ORPSensor, + OxxygenSensor, + TemperatureSensor, + pHSensor, + TurbiditySensor, +) +from parsers import BoardData, ParserStrategy +from logger import get_logger + + +_LOGGER = get_logger(__name__) + + +class BoardStatus: + Connected: str = "подключено" + Disconnected: str = "не подключено" + Connection: str = "подключение..." + + +class Board: + def __init__(self, sensors): + self._message_id: str = "" + self._sensor_objects = sensors + self._board_data = BoardData() + self._parser_strategy = None + self._connected_sockets: tp.Dict[str, int] = {} + self._sensors = {} + self._sockets = {} + for sensor in self._sensor_objects: + self._sensors[sensor.get_name()] = sensor + + def set_signals( + self, + data_update, + coeffs_update, + battery_update, + info_update, + calibration_progress, + restart + ) -> None: + self._parser_strategy = ParserStrategy( + data_update, + coeffs_update, + battery_update, + info_update, + calibration_progress, + restart, + ) + + def parser(self, data: str) -> bool: + return self._parser_strategy.get_parser(data, self._message_id).parse( + self._board_data + ) + + def update_connected_sockets(self, connected_sockets: tp.Dict): + self._connected_sockets = connected_sockets + + def get_sensors_data(self) -> tp.Dict: + sensors_data = {} + for sensor_name in self._connected_sockets: + sensors_data[sensor_name] = self._board_data.sensors_data[ + self._connected_sockets[sensor_name] + ] + return sensors_data + + def get_calibration_coeffs(self, sensor_name: str) -> tp.Dict: + return self._board_data.calibration_coeffs[self._connected_sockets[sensor_name]] + + def get_board_info(self) -> tp.Dict: + return self._board_data.board_info + + def check_message_id(self, data: str) -> bool: + return data.startswith(f"${self._message_id}") + + def get_show_coeff_command(self) -> (bytes, tp.Optional[str]): + return b"z", "#z" + + def get_board_info_command(self) -> (bytes, tp.Optional[str]): + return b"f", "#f" + + def get_set_counter_command(self, duration: int) -> (bytes, tp.Optional[str]): + return f"t{duration}".encode(), "#t" + + def get_sensor_names(self): + return [sensor.get_name() for sensor in self._sensor_objects] + + def get_sensor_units(self, sensor_name: str) -> str: + return self._sensors[sensor_name].get_units() + + def get_sensor_calibration_solutions(self, sensor_name: str) -> tp.List[str]: + return self._sensors[sensor_name].get_calibration_solutions() + + def get_calibration_command( + self, sensor_name: str = None + ) -> (bytes, tp.Optional[str]): + pass + + def get_socket_sensors(self, socket: int) -> tp.List[str]: + return self._sockets[socket] + + def get_battery_level(self) -> int: + return self._board_data.battery_level + + +class SWBoard(Board): + def __init__(self): + super().__init__( + [ + TemperatureSensor(), + pHSensor(), + ConductivitySensor(), + OxxygenSensor(), + ORPSensor(), + TurbiditySensor(), + ] + ) + self._message_id = "w" + self._sockets = { + 1: ["Датчик рН"], + 2: ["Датчик кислорода"], + 3: ["Датчик проводимости"], + 4: ["Датчик температуры"], + 5: ["Датчик ОВП"], + 6: ["Датчик мутности"], + } + + def get_calibration_command( + self, calibration_solution: str, sensor_name: str = None + ) -> (bytes, tp.Optional[str]): + return ( + self._sensors[sensor_name].get_calibration_command(calibration_solution), + "#?", + ) + + +class SWIonsBoard(Board): + def __init__(self): + super().__init__( + [ + NO2Sensor(), + NO3Sensor(), + NH4Sensor(), + ClSensor(), + TemperatureSensor(), + ] + ) + self._message_id = "i" + self._socket_calibration_commands = { + 1: ["a", "b", "c"], + 2: ["k", "l", "m"], + 3: ["n", "o", "p"], + 4: ["q", "r", "s"], + } + self._sockets = { + 1: ["Датчик NH4", "Датчик NO3", "Датчик NO2", "Датчик Cl"], + 2: ["Датчик NO3", "Датчик NO2", "Датчик NH4", "Датчик Cl"], + 3: ["Датчик NO2", "Датчик NO3", "Датчик NH4", "Датчик Cl"], + 4: ["Датчик Cl", "Датчик NO3", "Датчик NH4", "Датчик NO2"], + 5: [], + 6: ["Датчик температуры"], + } + + def get_calibration_command( + self, calibration_solution: str, sensor_name: str = None + ) -> (bytes, tp.Optional[str]): + consentration, solution_number = self._sensors[sensor_name].get_consentration( + calibration_solution + ) + socket_command = self._socket_calibration_commands[ + self._connected_sockets[sensor_name] + ][solution_number] + return f"{socket_command}{consentration}".encode(), "#?" + + def get_multiions_calibration_command(self, sensors_on_sockets) -> str: + pass diff --git a/app/gui/mainwindow.ui b/app/gui/mainwindow.ui new file mode 100644 index 0000000..63f937d --- /dev/null +++ b/app/gui/mainwindow.ui @@ -0,0 +1,873 @@ + + + MainWindow + + + + 0 + 0 + 521 + 631 + + + + SmartWaterGUI + + + false + + + + + + 10 + 60 + 501 + 521 + + + + 0 + + + + Текущие измерения + + + + + 10 + 50 + 421 + 403 + + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + + + + + Гнездо 1 + + + true + + + + + + + 10 + + + + + + Датчик температуры + + + + + + + + + 130 + 30 + + + + + + + + + 50 + 16777215 + + + + + + + + + + + + + + + QLayout::SetDefaultConstraint + + + + + Гнездо 2 + + + true + + + + + + + 10 + + + QLayout::SetDefaultConstraint + + + + + + Датчик рН + + + + + + + + + 130 + 30 + + + + + + + + + 50 + 16777215 + + + + ед. рН + + + + + + + + + + + + + Гнездо 3 + + + true + + + + + + + 10 + + + + + + Датчик проводимости + + + + + + + + + 130 + 30 + + + + + + + + + 50 + 16777215 + + + + мкСм + + + + + + + + + + + + + Гнездо 4 + + + true + + + + + + + 10 + + + + + + Датчик кислорода + + + + + + + + + 130 + 30 + + + + + + + + + 50 + 16777215 + + + + % + + + + + + + + + + + + + Гнездо 5 + + + true + + + + + + + 10 + + + + + + Датчик ОВП + + + + + + + + + 130 + 30 + + + + + + + + + 50 + 16777215 + + + + мВ + + + + + + + + + + + + + Гнездо 6 + + + false + + + + + + + 10 + + + + + + Датчик мутности + + + + + + + + + 130 + 30 + + + + + + + + + 50 + 16777215 + + + + NTU + + + + + + + + + + + + + 10 + 10 + 111 + 31 + + + + Smart Water + + + true + + + + + + 140 + 10 + 141 + 31 + + + + Smart Water Ions + + + + + + Калибровка + + + + + 270 + 10 + 211 + 31 + + + + + + + 10 + 16 + 71 + 21 + + + + Датчик + + + + + + 10 + 50 + 181 + 31 + + + + Калибровочный раствор + + + + + + 270 + 50 + 211 + 31 + + + + + + + 150 + 140 + 211 + 41 + + + + Начать калибровку + + + + + + 10 + 90 + 181 + 31 + + + + Время стабилизации + + + + + + 270 + 90 + 211 + 31 + + + + + 1 минута + + + + + 2 минуты + + + + + 3 минуты + + + + + 4 минуты + + + + + 5 минут + + + + + + + 10 + 440 + 471 + 31 + + + + 24 + + + + + + 10 + 260 + 161 + 151 + + + + + + + 10 + 210 + 151 + 21 + + + + Калибровочные + + + + + + 10 + 230 + 151 + 21 + + + + значения: + + + + + + 179 + 209 + 301 + 221 + + + + + + + Информация об устройстве + + + + + 10 + 10 + 221 + 21 + + + + + 75 + true + + + + Информация об устройстве + + + + + + 10 + 50 + 481 + 171 + + + + + + + + + + 180 + 16777215 + + + + Имя устройства: + + + + + + + ... + + + + + + + + + + + + 180 + 16777215 + + + + Serial ID: + + + + + + + ... + + + + + + + + + + + + 180 + 16777215 + + + + Прошивка: + + + + + + + ... + + + + + + + + + + + + 180 + 16777215 + + + + Версия прошивки: + + + + + + + ... + + + + + + + + + + + + 180 + 16777215 + + + + md5 hash: + + + + + + + ... + + + + + + + + + + + + + 10 + 20 + 81 + 31 + + + + USB Порт + + + + + + 90 + 20 + 211 + 31 + + + + + + + 340 + 574 + 171 + 31 + + + + + 9 + + + + SmartWaterGUI версия ПО 2.0 + + + + + + 410 + 20 + 51 + 31 + + + + Заряд: + + + + + + 460 + 20 + 31 + 31 + + + + Qt::LeftToRight + + + ... + + + Qt::AlignCenter + + + + + + 490 + 20 + 21 + 31 + + + + % + + + Qt::AlignCenter + + + + + + 10 + 580 + 61 + 21 + + + + Статус: + + + + + + 70 + 580 + 121 + 21 + + + + не подключено + + + + + + + + PlotWidget + QWidget +
pyqtgraph
+ 1 +
+
+ + +
diff --git a/app/libelium-calibration.py b/app/libelium-calibration.py new file mode 100644 index 0000000..b8d3655 --- /dev/null +++ b/app/libelium-calibration.py @@ -0,0 +1,292 @@ +import sys +import typing as tp + +from PyQt5 import QtGui, QtWidgets +import pyqtgraph as pg + +from boards import SWBoard, SWIonsBoard, BoardStatus +from sensors_const import MULTIIONS_SOLUTIONS, SW_BOARD_TYPE, SWIONS_BOARD_TYPE +from workers import BoardSerial, PortDetectThread +from logger import get_logger +from gui.mainwindow import Ui_MainWindow + + +_LOGGER = get_logger(__name__) + + +class Calibration: + def __init__(self, main_window: QtWidgets.QMainWindow): + self.main_window = main_window + self.button = main_window.pushButtonStartCalibration + self.progress_bar = main_window.progressBarCalibration + self.graphics_view = main_window.graphicsViewCalibration + self.board_serial = main_window.board_serial + self.duration: int = ( + int(main_window.boxStabilisationTime.currentText().split()[0]) * 10 * 2 + ) + self.progress_bar.setMinimum(0) + self.progress_bar.setMaximum(self.duration) + self.board_serial.calibrationProgressUpdate.connect( + self._progress_update + ) + self.board_serial.restartSignal.connect(self._start_calibration) + self._start_calibration() + self.button.setEnabled(False) + + def _start_calibration(self): + sensor_name = self.main_window.boxSensors.currentText() + solution = self.main_window.boxCalibrationSolution.currentText() + self._setup_graphics() + self.board_serial.start_calibration(sensor_name, solution, self.duration) + + def _setup_graphics(self): + self.graphics_view.clear() + self.pen = pg.mkPen(color=(255, 0, 0), width=3) + self.graphics_view.setXRange(0, self.duration) + self.line = None + self.steps = [] + self.values = [] + + def _progress_update(self, data): + _LOGGER.debug(f"Progress update: {data['step']}") + self.progress_bar.setValue(data["step"] + 1) + self._draw_graphics(data) + if data["step"] == (self.duration - 1): + self._finish_calibration() + + def _finish_calibration(self): + self.button.setEnabled(True) + self.board_serial.calibrationProgressUpdate.disconnect() + self.board_serial.restartSignal.disconnect() + + def _draw_graphics(self, data): + self.steps.append(data["step"]) + self.values.append(data["value"]) + if self.line is None: + self.line = self.graphics_view.plot(self.steps, self.values, pen=self.pen, symbol="o", symbolSize=5, symbolBrush="r") + else: + self.line.setData(self.steps, self.values) + + +class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): + def __init__(self, parent=None, app=None): + super(MainWindow, self).__init__(parent) + self.setupUi(self) + self.board_serial = None + self.board_status = BoardStatus.Disconnected + self.current_board_type: str = SW_BOARD_TYPE + self.boards = {SW_BOARD_TYPE: SWBoard(), SWIONS_BOARD_TYPE: SWIonsBoard()} + self.current_board: str = self.boards[SW_BOARD_TYPE] + self.current_sensor_calibration: str = "" + self.port_detect: PortDetectThread = PortDetectThread() + self.port_detect.portsUpdate.connect(self.populate_boards) + self.port_detect.start() + self.boxUSBPorts.currentTextChanged.connect(self.choose_port) + self.boxSensors.currentTextChanged.connect(self.choose_sensor_calibration) + self.radioButtonSW.toggled.connect(self.sw_swions_switched) + self.pushButtonStartCalibration.clicked.connect(self.handle_calibration_button) + self.progressBarCalibration.setValue(0) + self.sensors_gui: list = [ + ( + self.comboBoxSensor_1, + self.checkBoxSensor_1, + self.dataMeasSensor_1, + self.labelUnitsSensor_1, + ), + ( + self.comboBoxSensor_2, + self.checkBoxSensor_2, + self.dataMeasSensor_2, + self.labelUnitsSensor_2, + ), + ( + self.comboBoxSensor_3, + self.checkBoxSensor_3, + self.dataMeasSensor_3, + self.labelUnitsSensor_3, + ), + ( + self.comboBoxSensor_4, + self.checkBoxSensor_4, + self.dataMeasSensor_4, + self.labelUnitsSensor_4, + ), + ( + self.comboBoxSensor_5, + self.checkBoxSensor_5, + self.dataMeasSensor_5, + self.labelUnitsSensor_5, + ), + ( + self.comboBoxSensor_6, + self.checkBoxSensor_6, + self.dataMeasSensor_6, + self.labelUnitsSensor_6, + ), + ] + self.change_sensor_board(self.current_board_type) + for sensor in self.sensors_gui: + sensor[1].stateChanged.connect(self.sensor_enabled_changed) + sensor[0].currentTextChanged.connect(self.sensors_sockets_changed) + self._update_connected_sockets() + self.sensors_enabled: tp.List[str] = [] + self.populate_sensors_on_calibration() + self._setup_graphic() + self.show() + + def _setup_graphic(self): + self.graphicsViewCalibration.setBackground("w") + self.graphicsViewCalibration.showGrid(x=True, y=True) + + def handle_calibration_button(self): + if self.board_status == BoardStatus.Connected: + self.calibration = Calibration(self) + + def sensors_sockets_changed(self, data): + self._update_connected_sockets() + + def _update_connected_sockets(self): + i = 1 + connected_sockets = {} + for sensor in self.sensors_gui: + connected_sockets[sensor[0].currentText()] = i + i += 1 + self.current_board.update_connected_sockets(connected_sockets) + + def populate_sensors_on_calibration(self): + self.sensors_enabled = [] + for checkbox in self.sensors_gui: + if checkbox[1].checkState() and checkbox[0].currentText() != "": + self.sensors_enabled.append(checkbox[0].currentText()) + self.boxSensors.clear() + self.boxSensors.addItems(self.sensors_enabled) + if self.board_status == BoardStatus.Connected: + self._update_sensors_meas() + if self.radioButtonSWIons.isChecked(): + self.boxSensors.addItem("Multi Ions (NO3, NH4, Cl)") + + def choose_sensor_calibration(self, sensor: str): + self.current_sensor_calibration = sensor + self.boxCalibrationSolution.clear() + if sensor in self.current_board.get_sensor_names(): + self.boxCalibrationSolution.addItems( + self.current_board.get_sensor_calibration_solutions(sensor) + ) + else: + self.boxCalibrationSolution.addItems(MULTIIONS_SOLUTIONS) + if self.board_status == BoardStatus.Connected: + self._update_calibration_coeffs() + + def sw_swions_switched(self): + _LOGGER.debug( + f"SW: {self.radioButtonSW.isChecked()}, SW Ions: {self.radioButtonSWIons.isChecked()}" + ) + self.change_sensor_board( + SW_BOARD_TYPE if self.radioButtonSW.isChecked() else SWIONS_BOARD_TYPE + ) + self.populate_sensors_on_calibration() + + def set_sensors_units(self): + for sensor in self.sensors_gui: + sensor_name = sensor[0].currentText() + if sensor_name != "": + sensor[3].setText(self.current_board.get_sensor_units(sensor_name)) + else: + sensor[3].setText("") + + def change_sensor_board(self, board_type: str): + self.current_board_type = board_type + self.current_board = self.boards[board_type] + socket_number = 1 + for socket in self.sensors_gui: + socket[0].clear() + socket[0].addItems(self.current_board.get_socket_sensors(socket_number)) + if self.current_board.get_socket_sensors(socket_number) == []: + socket[1].setEnabled(False) + else: + socket[1].setEnabled(True) + socket_number += 1 + self.set_sensors_units() + + def sensor_enabled_changed(self, state: int): + _LOGGER.debug(f"Checkbox state changed: {state}") + self.populate_sensors_on_calibration() + + def _update_sensors_meas(self) -> None: + sensors_data = self.current_board.get_sensors_data() + for sensor in self.sensors_gui: + if sensor[1].checkState(): + sensor[2].setText(str(sensors_data.get(sensor[0].currentText(), ""))) + sensor[2].setEnabled(True) + else: + sensor[2].setEnabled(False) + sensor[2].setText("") + + def _update_battery(self) -> None: + battery_data = self.current_board.get_battery_level() + self.dataBattery.setText(str(battery_data)) + + def _update_board_info(self) -> None: + board_info = self.current_board.get_board_info() + self.dataDeviceName.setText(board_info["name"]) + self.dataSerialID.setText(board_info["serial_id"]) + self.dataFirmware.setText(board_info["firmware"]) + self.dataFirmwareVersion.setText(board_info["firmware_version"]) + self.datamd5.setText(board_info["md5_hash"]) + + def _update_calibration_coeffs(self) -> None: + current_sensor = self.boxSensors.currentText() + text = f"Раствор - значение\n" + if current_sensor == "": + self.textCalibrationValues.setText(text) + return + calibration_coeffs = self.current_board.get_calibration_coeffs(current_sensor) + for value in calibration_coeffs: + text += f"{value} - {calibration_coeffs[value]}\n" + self.textCalibrationValues.setText(text) + + def _update_board_status(self, board_status: str): + self.board_status = board_status + self.dataStatus.setText(board_status) + + def populate_boards(self, ports: tp.List[str]): + self.boxUSBPorts.clear() + if self.boxUSBPorts.currentText() == "" and len(ports) > 0: + self.boxUSBPorts.setCurrentIndex(0) + if len(ports) > 0: + self.boxUSBPorts.addItems([p.name for p in ports]) + else: + sep = QtGui.QStandardItem("Платы не найдены") + sep.setEnabled(False) + self.boxUSBPorts.model().appendRow(sep) + + def chose_curent_board(self, board_type: str): + self.current_board = self.boards[board_type] + if board_type == SW_BOARD_TYPE and not self.radioButtonSW.isChecked(): + self.radioButtonSW.toggle() + elif board_type == SWIONS_BOARD_TYPE and not self.radioButtonSWIons.isChecked(): + self.radioButtonSWIons.toggle() + self.radioButtonSW.setEnabled(False) + self.radioButtonSWIons.setEnabled(False) + + def choose_port(self, port): + _LOGGER.debug(f"New port chosen: {port}") + if port != "Платы не найдены" and port != "": + if self.board_serial is not None: + self.board_serial.close_connection() + self.board_serial = BoardSerial(port, self.boards) + self.board_serial.dataUpdate.connect(self._update_sensors_meas) + self.board_serial.batteryUpdate.connect(self._update_battery) + self.board_serial.infoUpdate.connect(self._update_board_info) + self.board_serial.currentBoardUpdate.connect(self.chose_curent_board) + self.board_serial.coeffsUpdate.connect(self._update_calibration_coeffs) + self.board_serial.boardStatusUpdate.connect(self._update_board_status) + self.board_serial.start() + else: + self.radioButtonSW.setEnabled(True) + self.radioButtonSWIons.setEnabled(True) + + +app = QtWidgets.QApplication(sys.argv) +window = MainWindow() +app.exec_() diff --git a/app/logger.py b/app/logger.py new file mode 100644 index 0000000..f3cd693 --- /dev/null +++ b/app/logger.py @@ -0,0 +1,11 @@ +import logging +import sys + +def get_logger(name: str): + logger = logging.getLogger(name) + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler(stream=sys.stdout) + formatter = logging.Formatter("%(name)s %(asctime)s %(levelname)s %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + return logger \ No newline at end of file diff --git a/app/parsers.py b/app/parsers.py new file mode 100644 index 0000000..90d4f04 --- /dev/null +++ b/app/parsers.py @@ -0,0 +1,197 @@ +import typing as tp +from logger import get_logger + +_LOGGER = get_logger(__name__) + +class BoardData: + def __init__(self): + self.sensors_data: tp.Dict[int, tp.Optional[float]] = { + 1: None, + 2: None, + 3: None, + 4: None, + 5: None, + 6: None, + } + self.board_info: tp.Dict[str, str] = { + "name": None, + "serial_id": None, + "firmware": None, + "firmware_version": None, + "md5_hash": None, + } + self.battery_level: int = 0 + self.calibration_coeffs: tp.Dict[int, tp.Dict] = { + 1: {}, + 2: {}, + 3: {}, + 4: {}, + 5: {}, + 6: {}, + } + +class Parser: + def __init__(self, data: str, signals: tp.List = None): + self.signals = signals + self.data = data + + def emit_signals(func: tp.Callable): + def wrapper(self, *args, **kwargs): + resp = func(self, *args, **kwargs) + for signal in self.signals: + signal.emit() + return resp + return wrapper + + @emit_signals + def parse(self, board_data: BoardData) -> bool: + return True + +class ParserStrategy: + def __init__( + self, + data_update, + coeffs_update, + battery_update, + info_update, + calibration_progress, + restart, + ): + self._data_update_signal = data_update + self._coeffs_update_signal = coeffs_update + self._battery_update_signal = battery_update + self._info_update_signal = info_update + self._calibration_progress_signal = calibration_progress + self._restart_signal = restart + self._measure_signal = "$measure" + self._coeffs_prefix = "#z" + self._info_prefix = "#f" + self._calibration_prefix = "^|" + self._restart_prefix = "J#" + + def get_parser(self, data: str, message_id: str) -> Parser: + _LOGGER.debug(f"Parser strategy get {data}") + if self._restart_prefix in data: + _LOGGER.debug("Restart parser") + return RestartParser(data, [self._restart_signal]) + elif data.startswith(self._coeffs_prefix): + if message_id == "w": + return SWCoeffParser(data, [self._coeffs_update_signal]) + elif message_id == "i": + return SWIonsCoeffParser(data, [self._coeffs_update_signal]) + elif data.startswith(self._info_prefix): + return BoardInfoParser(data, [self._info_update_signal]) + elif data.startswith(f"${message_id}"): + if message_id == "w": + return SWDataParser(data, [self._data_update_signal, self._battery_update_signal]) + elif message_id == "i": + return SWIonsDataParser(data, [self._data_update_signal, self._battery_update_signal]) + elif data.startswith(self._calibration_prefix): + return CalibrationParser(data, [self._calibration_progress_signal]) + elif self._measure_signal in data: + return StartMeasureParser(data) + else: + return TrueParser(data) + +class RestartParser(Parser): + @Parser.emit_signals + def parse(self, board_data: BoardData) -> bool: + return False + +class TrueParser(Parser): + def parse(self, board_data: BoardData) -> bool: + return True + +class StartMeasureParser(Parser): + def parse(self, board_data: BoardData) -> bool: + return False + +class SWDataParser(Parser): + @Parser.emit_signals + def parse(self, board_data: BoardData) -> bool: + _LOGGER.debug(f"Data parser got {self.data}") + values = self.data.split("|") + for i in range(1, 7): + board_data.sensors_data[i] = round(float(values[i]), 3) + board_data.battery_level = int(values[7]) + return True + +class SWIonsDataParser(Parser): + @Parser.emit_signals + def parse(self, board_data: BoardData) -> bool: + _LOGGER.debug(f"Data parser got {self.data}") + values = self.data.split("|") + for i in range(2, 6): + board_data.sensors_data[i-1] = round(float(values[i]), 3) + board_data.sensors_data[6] = round(float(values[1]), 3) + board_data.battery_level = int(values[6]) + return True + +class BoardInfoParser(Parser): + @Parser.emit_signals + def parse(self, board_data: BoardData) -> bool: + _LOGGER.debug(f"Info parser got {self.data}") + values = self.data.split("|") + board_data.board_info["name"] = values[1] + board_data.board_info["serial_id"] = values[2] + board_data.board_info["firmware_version"] = values[3] + board_data.board_info["md5_hash"] = values[4] + board_data.board_info["firmware"] = values[5] + return True + +class CalibrationParser(Parser): + def parse(self, board_data: BoardData) -> None: + if "^|finished" in self.data: + return True + values = self.data[2:].split(" - ") + self.signals[0].emit({"step": int(values[0]), "value": round(float(values[1].split("\\")[0]), 3)}) + return False + +class SWCoeffParser(Parser): + @Parser.emit_signals + def parse(self, board_data: BoardData) -> bool: + _LOGGER.debug(f"Coeffs parser got {self.data}") + coeffs = [] + for value in self.data.split("|"): + coeffs_sensor = [] + for coeff in value.split(","): + coeffs_sensor.append(coeff) + coeffs.append(coeffs_sensor) + for coeff in coeffs[1]: + board_data.calibration_coeffs[1][coeff.split("-")[0]] = round(float(coeff.split("-")[1]), 3) + board_data.calibration_coeffs[1]["Температура"] = round(float(coeffs[4][0]), 1) + for coeff in coeffs[2]: + board_data.calibration_coeffs[2][coeff.split("-")[0]] = round(float(coeff.split("-")[1]), 3) + for coeff in coeffs[3]: + board_data.calibration_coeffs[3][coeff.split("-")[0]] = round(float(coeff.split("-")[1]), 1) + for coeff in coeffs[5]: + board_data.calibration_coeffs[5][coeff.split("-")[0]] = round(float(coeff.split("-")[1]), 0) + return True + +class SWIonsCoeffParser(Parser): + @Parser.emit_signals + def parse(self, board_data: BoardData) -> bool: + _LOGGER.debug(f"Coeffs parser got {self.data}") + coeffs = [] + for value in self.data.split("|"): + coeffs_sensor = [] + for coeff in value.split(","): + coeffs_sensor.append(coeff) + coeffs.append(coeffs_sensor) + board_data.calibration_coeffs[1] = {} + for coeff in coeffs[1]: + solution = f"{int(float(coeff.split('-')[0].split()[0]))} {coeff.split('-')[0].split()[1]}" + board_data.calibration_coeffs[1][solution] = round(float(coeff.split("-")[1]), 3) + board_data.calibration_coeffs[2] = {} + for coeff in coeffs[2]: + solution = f"{int(float(coeff.split('-')[0].split()[0]))} {coeff.split('-')[0].split()[1]}" + board_data.calibration_coeffs[2][solution] = round(float(coeff.split("-")[1]), 3) + board_data.calibration_coeffs[3] = {} + for coeff in coeffs[3]: + solution = f"{int(float(coeff.split('-')[0].split()[0]))} {coeff.split('-')[0].split()[1]}" + board_data.calibration_coeffs[3][solution] = round(float(coeff.split("-")[1]), 3) + board_data.calibration_coeffs[4] = {} + for coeff in coeffs[4]: + solution = f"{int(float(coeff.split('-')[0].split()[0]))} {coeff.split('-')[0].split()[1]}" + board_data.calibration_coeffs[4][solution] = round(float(coeff.split("-")[1]), 3) + return True \ No newline at end of file diff --git a/app/sensors.py b/app/sensors.py new file mode 100644 index 0000000..9b59acd --- /dev/null +++ b/app/sensors.py @@ -0,0 +1,176 @@ +import typing as tp +from logger import get_logger + + +_LOGGER = get_logger(__name__) + + +class Sensor: + def __init__(self): + self._name = "" + self._units = "" + self._calibration_solutions = [] + + def get_name(self) -> str: + return self._name + + def get_units(self) -> str: + return self._units + + def get_calibration_solutions(self) -> tp.List[str]: + return self._calibration_solutions + + def get_calibration_command(self, calibration_solution: str) -> tp.Optional[str]: + return None + + def get_consentration(self, calibration_solution: str) -> (tp.Optional[str], int): + return None + + +class TemperatureSensor(Sensor): + def __init__(self): + self._name = "Датчик температуры" + self._units = "℃" + self._calibration_solutions = [] + + +class pHSensor(Sensor): + def __init__(self): + self._name = "Датчик рН" + self._units = "ед. рН" + self._calibration_solutions = ["p4", "p7", "p10"] + self._calibration_commands = {"p4": b"r", "p7": b"q", "p10": b"p"} + + def get_calibration_command(self, calibration_solution: str) -> tp.Optional[str]: + return self._calibration_commands.get(calibration_solution) + + +class ConductivitySensor(Sensor): + def __init__(self): + self._name = "Датчик проводимости" + self._units = "мкСм" + self._calibration_solutions = [ + "84 мкСм (пара 84 и 1413)", + "1413 мкСм (пара 84 и 1413)", + "12880 мкСм (пара 12880 и 80000)", + "80000 мкСм (пара 12880 и 80000)", + "12880 мкСм (пара 12880 и 150000)", + "150000 мкСм (пара 12880 и 150000)", + ] + self._calibration_commands = { + "84 мкСм (пара 84 и 1413)": b"a", + "1413 мкСм (пара 84 и 1413)": b"k", + "12880 мкСм (пара 12880 и 80000)": b"c", + "80000 мкСм (пара 12880 и 80000)": b"m", + "12880 мкСм (пара 12880 и 150000)": b"b", + "150000 мкСм (пара 12880 и 150000)": b"l", + } + + def get_calibration_command(self, calibration_solution: str) -> tp.Optional[str]: + return self._calibration_commands.get(calibration_solution) + + +class OxxygenSensor(Sensor): + def __init__(self): + self._name = "Датчик кислорода" + self._units = "%" + self._calibration_solutions = ["0%", "100%"] + self._calibration_commands = {"0%": b"o", "100%": b"n"} + + def get_calibration_command(self, calibration_solution: str) -> tp.Optional[str]: + return self._calibration_commands.get(calibration_solution) + + +class ORPSensor(Sensor): + def __init__(self): + self._name = "Датчик ОВП" + self._units = "мВ" + self._calibration_solutions = ["225 мВ"] + self._calibration_commands = {"225 мВ": b"s"} + + def get_calibration_command(self, calibration_solution: str) -> tp.Optional[str]: + return self._calibration_commands.get(calibration_solution) + + +class TurbiditySensor(Sensor): + def __init__(self): + self._name = "Датчик мутности" + self._units = "NTU" + self._calibration_solutions = ["0 NTU", "10 NTU", "40 NTU"] + self._calibration_commands = {"0 NTU": b"", "10 NTU": b"", "40 NTU": b""} + + def get_calibration_command(self, calibration_solution: str) -> tp.Optional[str]: + return self._calibration_commands.get(calibration_solution) + + +class NO2Sensor(Sensor): + def __init__(self): + self._name = "Датчик NO2" + self._units = "мг/л" + self._calibration_solutions = ["10 мг/л", "100 мг/л", "1000 мг/л"] + + def get_consentration(self, calibration_solution: str) -> (tp.Optional[str], int): + return ( + calibration_solution.split()[0], + self._calibration_solutions.index(calibration_solution), + ) + + +class NO3Sensor(Sensor): + def __init__(self): + self._name = "Датчик NO3" + self._units = "мг/л" + self._calibration_solutions = [ + "10 мг/л", + "100 мг/л", + "1000 мг/л", + "Multi-Ion 1 (132 мг/л)", + "Multi-Ion 2 (660 мг/л)", + "Multi-Ion 2 (1320 мг/л)", + ] + + def get_consentration(self, calibration_solution: str) -> (tp.Optional[str], int): + if "Multi-Ion" in calibration_solution: + return calibration_solution.split()[2][1:], self._calibration_solutions.index(calibration_solution) - 3, + else: + return calibration_solution.split()[0], self._calibration_solutions.index(calibration_solution), + + +class NH4Sensor(Sensor): + def __init__(self): + self._name = "Датчик NH4" + self._units = "мг/л" + self._calibration_solutions = [ + "10 мг/л", + "100 мг/л", + "1000 мг/л", + "Multi-Ion 1 (4 мг/л)", + "Multi-Ion 2 (20 мг/л)", + "Multi-Ion 2 (40 мг/л)", + ] + + def get_consentration(self, calibration_solution: str) -> (tp.Optional[str], int): + if "Multi-Ion" in calibration_solution: + return calibration_solution.split()[2][1:], self._calibration_solutions.index(calibration_solution) - 3, + else: + return calibration_solution.split()[0], self._calibration_solutions.index(calibration_solution), + + +class ClSensor(Sensor): + def __init__(self): + self._name = "Датчик Cl" + self._units = "мг/л" + self._calibration_solutions = [ + "10 мг/л", + "100 мг/л", + "1000 мг/л", + "Multi-Ion 1 (75 мг/л)", + "Multi-Ion 2 (375 мг/л)", + "Multi-Ion 2 (750 мг/л)", + ] + + def get_consentration(self, calibration_solution: str) -> (tp.Optional[str], int): + if "Multi-Ion" in calibration_solution: + return calibration_solution.split()[2][1:], self._calibration_solutions.index(calibration_solution) - 3, + else: + return calibration_solution.split()[0], self._calibration_solutions.index(calibration_solution), diff --git a/app/sensors_const.py b/app/sensors_const.py new file mode 100644 index 0000000..04b2ee9 --- /dev/null +++ b/app/sensors_const.py @@ -0,0 +1,4 @@ +SW_BOARD_TYPE = "SW" +SWIONS_BOARD_TYPE = "SWIons" + +MULTIIONS_SOLUTIONS = ["Multi-Ion 1", "Multi-Ion 2", "Multi-Ion 3"] \ No newline at end of file diff --git a/app/workers.py b/app/workers.py new file mode 100644 index 0000000..11e68b4 --- /dev/null +++ b/app/workers.py @@ -0,0 +1,133 @@ +import time +import typing as tp + +import serial +import serial.tools.list_ports +from PyQt5 import QtCore +from boards import Board, BoardStatus + +from logger import get_logger + +BAUDRATE = 115200 + +_LOGGER = get_logger(__name__) + + +class PortDetectThread(QtCore.QThread): + interval = 1.0 + portsUpdate = QtCore.pyqtSignal([list]) + + def run(self): + """Checks list of available ports and emits signal when necessary""" + ports = None + while True: + new_ports = serial.tools.list_ports.comports() + if ports is None or [p.name for p in ports] != [p.name for p in new_ports]: + self.portsUpdate.emit(new_ports) + time.sleep(self.interval) + ports = new_ports + + + +class BoardSerial(QtCore.QThread): + interval = 0.1 + dataUpdate = QtCore.pyqtSignal() + coeffsUpdate = QtCore.pyqtSignal() + batteryUpdate = QtCore.pyqtSignal() + infoUpdate = QtCore.pyqtSignal() + calibrationProgressUpdate = QtCore.pyqtSignal(dict) + currentBoardUpdate = QtCore.pyqtSignal(str) + boardStatusUpdate = QtCore.pyqtSignal(str) + restartSignal = QtCore.pyqtSignal() + + def __init__(self, port: str, boards: tp.Dict[str, Board], parent=None): + super(QtCore.QThread, self).__init__(parent) + self._port_is_opened = True + if "tty" in port: + self.port: str = f"/dev/{port}" + else: + self.port: str = port + self.serial: serial.Serial = serial.Serial(self.port, BAUDRATE) + self.current_board = None + self._commands_queue = [] + self._allowed_send_command = False + self.boards = boards + self._wait_response = None + + def _define_board(self, data: str) -> None: + # Calls on first message from board + for board_type in self.boards: + if self.boards[board_type].check_message_id(data): + self.current_board = self.boards[board_type] + self.currentBoardUpdate.emit(board_type) + self.current_board.set_signals( + data_update=self.dataUpdate, + coeffs_update=self.coeffsUpdate, + battery_update=self.batteryUpdate, + info_update=self.infoUpdate, + calibration_progress=self.calibrationProgressUpdate, + restart=self.restartSignal, + ) + self.boardStatusUpdate.emit(BoardStatus.Connected) + break + else: + return + self._allowed_send_command = self.current_board.parser(data) + self.update_board_info() + self.update_calibration_coeff() + + def update_board_info(self) -> None: + _LOGGER.debug("Update board info call") + self._add_command_to_queue_or_send(self.current_board.get_board_info_command()) + + def update_calibration_coeff(self) -> None: + _LOGGER.debug("Update calibration coeffs call") + self._add_command_to_queue_or_send(self.current_board.get_show_coeff_command()) + + def start_calibration(self, sensor: str, solution: str, duration: int) -> QtCore.pyqtSignal: + self._add_command_to_queue_or_send(self.current_board.get_set_counter_command(duration)) + self._add_command_to_queue_or_send(self.current_board.get_calibration_command(solution, sensor)) + + def close_connection(self): + if self._port_is_opened: + self.serial.close() + self.boardStatusUpdate.emit(BoardStatus.Disconnected) + _LOGGER.info(f"Port {self.port} is closed") + self._port_is_opened = False + + def run(self): + while True: + if not self._port_is_opened: + break + try: + if self.serial.inWaiting() > 0: + new_line = str(self.serial.readline())[2:-1] + _LOGGER.debug(f"New serial line: {new_line}") + _LOGGER.debug(f"Wait response: {self._wait_response}") + if self._wait_response and new_line.startswith(self._wait_response): + self._commands_queue.pop(0) + self._wait_response = None + _LOGGER.debug(f"Commands queue after pop: {self._commands_queue}") + if self.current_board is not None: + self._allowed_send_command = self.current_board.parser(new_line) + else: + self.boardStatusUpdate.emit(BoardStatus.Connection) + self._allowed_send_command = self._define_board(new_line) + _LOGGER.debug(f"Allow send command: {self._allowed_send_command}") + if self._allowed_send_command and self._commands_queue: + self._send_command(self._commands_queue[0]) + time.sleep(self.interval) + except OSError: + self.close_connection() + + def _add_command_to_queue_or_send(self, command: tuple) -> None: + self._commands_queue.append(command) + if self._allowed_send_command: + self._send_command(command) + _LOGGER.debug(f"Send command queue: {self._commands_queue}") + + def _send_command(self, command: tuple) -> None: + self._wait_response = command[1] + self.serial.write(command[0]) + self._allowed_send_command = False + _LOGGER.debug(f"Command {command} was sent") diff --git a/firmware/smart_water_with_calibration.pde b/firmware/smart_water_with_calibration.pde new file mode 100644 index 0000000..f4ad205 --- /dev/null +++ b/firmware/smart_water_with_calibration.pde @@ -0,0 +1,846 @@ +#include +#include +#include + + +char check_md5[] = "64d73b68f07a8480ecdceeb437ef63b9"; +char filename[] = "SmartWater_FRMW_V1_2.hex"; +char node_ID[] = "Node_01"; + +// Выбор датчика температуры +// 0 - pt1000; +// 1 - датчик температуры, встроенный в датчик мутности +//!ПРИ ИСПОЛЬЗОВАНИИ ДАТЧИКА МУТНОСТИ ДАТЧИК ТЕМПЕРАТУРЫ pt1000 ДОЛЖЕН БЫТЬ ОТКЛЮЧЕН! +int TEMP_SENSOR_TYPE = 0; +int debug = 0; +// 0 - show nothing (calibration mode) +// 1 - show frame +// 2 - show data +int ShowData = 2; + + +// Время калибровки +int counter = 10; +int zadergka = 500; + + +//версия прошивки (хранится в EEPROM) +int addressFVMajor = 1025; +int addressFVMinor = 1026; +int FVMajor = 1; +int FVMinor = 2; +int auxFVMajor = 0; +int auxFVMinor = 0; + + +unsigned long timer = 0; +int command = 0; + + +float value_pH; // pH values in volts +float value_temp; // temp in celsius +float value_pH_calculated; +float value_orp; // orp in volts +float value_orp_calculated; +//float value_di; +float value_do; // oxygen in volts +float value_do_calculated; +float value_cond; // conductivity in Ohms +float value_cond_calculated; +float value_turbidity; + +//----------------------------------- +// калибровочные точки для pH датчика +float cal_point_10 = 1.985; +float cal_point_7 = 2.070; +float cal_point_4 = 2.227; +int addr_p10 = 1030; +int addr_p7 = 1035; +int addr_p4 = 1039; +long aux_p10 = 0; +long aux_p7 = 0; +long aux_p4 = 0; +//----------------------------------- +// Температура калибровки +float cal_temp = 23.7; +int addr_cal_temp = 1043; +long aux_cal_temp = 0; +//----------------------------------- +// оффсет для ORP датчика (показание - 0.225) +float calibration_offset = 0.015; +int addr_orp_offset = 1047; +long aux_orp_offset = 0; +//----------------------------------- +// показание датчика кислорода для нормального воздуха +float air_calibration = 2.65; +// нулевая точка для датчика кислорода (0%) +float zero_calibration = 0.0; +int addr_air_calib = 1051; +int addr_zero_air = 1055; +long aux_air_calib = 0; +long aux_zero_air = 0; +//----------------------------------- +// значение первого раствора для датчика проводимости +long point1_cond = 10500; +// значение второго раствора для датчика проводимости +long point2_cond = 40000; +// точка калибровки для первого раствора для датчика проводимости +float point1_cal = 197.00; +// точка калибровки для второго раствора для датчика проводимости +float point2_cal = 150.00; +int addr_p1_cond = 1059; +int addr_p2_cond = 1063; +int addr_p1 = 1067; +int addr_p2 = 1071; +long aux_p1_cond = 0; +long aux_p2_cond = 0; +long aux_p1 = 0; +long aux_p2 = 0; + + +pHClass pHSensor; +ORPClass ORPSensor; +//DIClass DISensor; +DOClass DOSensor; +conductivityClass ConductivitySensor; +pt1000Class TemperatureSensor; +turbidityClass Turbidity; + +void setup() +{ + USB.ON(); + + cal_point_10 = LongToFloat(EEPROMReadLong(addr_p10)); + cal_point_7 = LongToFloat(EEPROMReadLong(addr_p7)); + cal_point_4 = LongToFloat(EEPROMReadLong(addr_p4)); + air_calibration = LongToFloat(EEPROMReadLong(addr_air_calib)); + zero_calibration = LongToFloat(EEPROMReadLong(addr_zero_air)); + point1_cond = EEPROMReadLong(addr_p1_cond); + point2_cond = EEPROMReadLong(addr_p2_cond); + point1_cal = LongToFloat(EEPROMReadLong(addr_p1)); + point2_cal = LongToFloat(EEPROMReadLong(addr_p2)); + cal_temp = LongToFloat(EEPROMReadLong(addr_cal_temp)); + calibration_offset = LongToFloat(EEPROMReadLong(addr_orp_offset)); + + Utils.writeEEPROM(addressFVMajor, FVMajor); + Utils.writeEEPROM(addressFVMinor, FVMinor); + auxFVMajor = Utils.readEEPROM(addressFVMajor); + auxFVMinor = Utils.readEEPROM(addressFVMajor); + + delay(5000); + + if (debug == 1) { + USB.println(cal_point_10); + USB.println(cal_point_7); + USB.println(cal_point_4); + USB.println(air_calibration); + USB.println(zero_calibration); + USB.println(point1_cond); + USB.println(point2_cond); + USB.println(point1_cal); + USB.println(point2_cal); + USB.println(cal_temp); + USB.println(calibration_offset); + } + + // Configure the calibration values + pHSensor.setCalibrationPoints(cal_point_10, cal_point_7, cal_point_4, cal_temp); + DOSensor.setCalibrationPoints(air_calibration, zero_calibration); + ConductivitySensor.setCalibrationPoints(point1_cond, point1_cal, point2_cond, point2_cal); +//------------------------------------------------------------------------------------------ + //----------------------------------------------------------------- + USB.flush(); +} + +void loop() +{ + /////////////////////////////////////////// + // 1. Turn on the board + /////////////////////////////////////////// + + if (ShowData == 2) { + SesorData(); + USB.flush(); + } + +// USB commands reading + timer = millis(); + while(millis()-timer < 5000) + { + if (USB.available() > 0) + { + command = USB.read(); + switch (command) { + case 65: // A + //USB.flush(); + ShowData = 0; + USB.println(F("#!")); + break; + case 66: //B + ShowData = 1; + USB.println(F("#+")); + break; + case 67: // C + ShowData = 2; + USB.println(F("#-")); + break; + case 121: // y + debug = 1; + break; + case 122: // z + ShowCoeff(); + case 100: // d + TEMP_SENSOR_TYPE = 1; + if (debug == 1) { USB.println(F("Temp from turbidity sensor")); } + break; + case 101: // e + TEMP_SENSOR_TYPE = 0; + if (debug == 1) { USB.println(F("temp from pt1000")); } + break; + case 116: // t + counter = USBGetInt(); + USB.println(F("#t")); + if (debug == 1) { USB.println(counter); } + break; + case 97: // a + //USB.flush(); + delay(1000); + USB.println(F("#?")); + //CondCalib_R1(220, 3000); + CondCalib_R1(84, 1413); + USB.println(F("#a")); + ShowCoeff(); + break; + case 98: // b + delay(1000); + USB.println(F("#?")); + //CondCalib_R1(10500, 40000); + CondCalib_R1(12880, 150000); + USB.println(F("#b")); + ShowCoeff(); + break; + case 99: // c + delay(1000); + USB.println(F("#?")); + //CondCalib_R1(62000, 90000); + CondCalib_R1(12880, 80000); + USB.println(F("#c")); + ShowCoeff(); + break; + case 107: // k + delay(1000); + USB.println(F("#?")); + //CondCalib_R2(220, 3000); + CondCalib_R2(84, 1413); + USB.println(F("#k")); + ShowCoeff(); + break; + case 108: // l + delay(1000); + USB.println(F("#?")); + //CondCalib_R2(10500, 40000); + CondCalib_R2(12880, 150000); + USB.println(F("#l")); + ShowCoeff(); + break; + case 109: // m + delay(1000); + USB.println(F("#?")); + //CondCalib_R2(62000, 90000); + CondCalib_R2(12880, 80000); + USB.println(F("#m")); + ShowCoeff(); + break; + case 110: // n + delay(1000); + USB.println(F("#?")); + OxygenCalib_100p(); + USB.println(F("#n")); + ShowCoeff(); + break; + case 111: // o + delay(1000); + USB.println(F("#?")); + OxygenCalib_0p(); + USB.println(F("#0")); + ShowCoeff(); + break; + case 112: // p + delay(1000); + USB.println(F("#?")); + pHSensorCalibP10(); + USB.println(F("#p")); + ShowCoeff(); + break; + case 113: // q + delay(1000); + USB.println(F("#?")); + pHSensorCalibP7(); + USB.println(F("#q")); + ShowCoeff(); + break; + case 114: // r + delay(1000); + USB.println(F("#?")); + pHSensorCalibP4(); + USB.println(F("#r")); + ShowCoeff(); + break; + case 115: // s + delay(1000); + USB.println(F("#?")); + ORPSensorCalib(); + USB.println(F("#s")); + ShowCoeff(); + break; + case 102: // f + auxFVMajor = Utils.readEEPROM(addressFVMajor); + auxFVMinor = Utils.readEEPROM(addressFVMajor); + //USB.print(F("Имя устройства: ")); + //USB.println(node_ID); + USB.print(F("#f|")); + //delay(1000); + //USB.println(); + USB.print(node_ID); + USB.print("|"); + ShowSerialNumber(); + USB.print("|"); + //USB.print(F("Версия прошивки: ")); + USB.print(auxFVMajor); + USB.print(F(".")); + //USB.println(auxFVMinor); + USB.print(auxFVMinor); + USB.print("|"); + USB.print(check_md5); + USB.print("|"); + USB.print(filename); + USB.println(F("|")); + break; + default: + //USB.println(F("Wrong command!")); + break; + } + USB.flush(); + + } + if (millis() < timer) + { + timer = millis(); + } + } + //frame.showFrame(); +} + +long USBGetLong() { + char number[10]; + int i = 0; + while (USB.available() > 0) { + number[i] = (char) USB.read(); + i++; + } + + long result = atol(number); + return result; +} + +int USBGetInt() { + char number[10]; + int i = 0; + while (USB.available() > 0) { + number[i] = (char) USB.read(); + i++; + } + + int result = atoi(number); + return result; +} + +long FloatToLong(float val) { + long a = val * 1000; + return a; +} + +float LongToFloat(long val1) { + float b = (float) val1/1000.0; + return b; +} + +//запись в EEPROM данных типа long +void EEPROMWriteLong(int address, long value) { + byte four = (value & 0xFF); + byte three = ((value >> 8) & 0xFF); + byte two = ((value >> 16) & 0xFF); + byte one = ((value >> 24) & 0xFF); + + Utils.writeEEPROM(address, four); + Utils.writeEEPROM(address + 1, three); + Utils.writeEEPROM(address + 2, two); + Utils.writeEEPROM(address + 3, one); +} + +//чтение из EEPROM данных типа long +long EEPROMReadLong(int address1) { + long four = Utils.readEEPROM(address1); + long three = Utils.readEEPROM(address1 + 1); + long two = Utils.readEEPROM(address1 + 2); + long one = Utils.readEEPROM(address1 + 3); + + return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF); +} + +//-------------------------------------- +// Выбор с какого датчика читаем температуру с одного из двух датчиков +float readTemp() { + float val_temp = 0.0; + if (TEMP_SENSOR_TYPE == 1) + { + val_temp = Turbidity.getTemperature(); + } + else + { + val_temp = TemperatureSensor.readTemperature(); + } + + return val_temp; +} + +//-------------------------------------- +// автоматический выбор датчика температуры (тестовая функция!) +float readTempAuto() { + float val_temp1 = 0.0; + val_temp1 = Turbidity.getTemperature(); + if (val_temp1 == -1000.0) + { + val_temp1 = TemperatureSensor.readTemperature(); + } + return val_temp1; + +} + +//-------------------------------------- +// Калибровка рН датчика в растворе рН10 +void pHSensorCalibP10() { + float pH_val_ohm = 0.0; + float temp1 = 0.0; + aux_p10 = EEPROMReadLong(addr_p10); + aux_p7 = EEPROMReadLong(addr_p7); + aux_p4 = EEPROMReadLong(addr_p4); + aux_cal_temp = EEPROMReadLong(addr_cal_temp); + pHSensor.setCalibrationPoints(LongToFloat(aux_p10), LongToFloat(aux_p7), LongToFloat(aux_p4), LongToFloat(aux_cal_temp)); + Water.ON(); + + for (int i = 0; i < counter; i++) { + pH_val_ohm = pHSensor.readpH(); + //temp1 = readTemp(); + temp1 = readTempAuto(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(pH_val_ohm); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_p10, FloatToLong(pH_val_ohm)); + EEPROMWriteLong(addr_cal_temp, FloatToLong(temp1)); + //EEPROMWriteLong(addr_p7, FloatToLong(aux_p7)); + //EEPROMWriteLong(addr_p4, FloatToLong(aux_p4)); + pHSensor.setCalibrationPoints(pH_val_ohm, LongToFloat(aux_p7), LongToFloat(aux_p4), temp1); + if (debug == 1) { + USB.println(F("Калибровка для раствора pH10 завершена.")); + } +} + +//-------------------------------------- +// Калибровка рН датчика в растворе рН7 +void pHSensorCalibP7() { + float pH_val_ohm = 0.0; + float temp1 = 0.0; + aux_p10 = EEPROMReadLong(addr_p10); + aux_p7 = EEPROMReadLong(addr_p7); + aux_p4 = EEPROMReadLong(addr_p4); + aux_cal_temp = EEPROMReadLong(addr_cal_temp); + pHSensor.setCalibrationPoints(LongToFloat(aux_p10), LongToFloat(aux_p7), LongToFloat(aux_p4), LongToFloat(aux_cal_temp)); + Water.ON(); + + for (int i = 0; i < counter; i++) { + pH_val_ohm = pHSensor.readpH(); + //temp1 = readTemp(); + temp1 = readTempAuto(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(pH_val_ohm); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_p7, FloatToLong(pH_val_ohm)); + //EEPROMWriteLong(addr_p7, FloatToLong(aux_p7)); + //EEPROMWriteLong(addr_p4, FloatToLong(aux_p4)); + pHSensor.setCalibrationPoints(LongToFloat(aux_p10), pH_val_ohm, LongToFloat(aux_p4), temp1); + if (debug == 1) { + USB.println(F("Калибровка для раствора pH7 завершена.")); + } +} + +//-------------------------------------- +// Калибровка рН датчика в растворе рН4 +void pHSensorCalibP4() { + float pH_val_ohm = 0.0; + float temp1 = 0.0; + aux_p10 = EEPROMReadLong(addr_p10); + aux_p7 = EEPROMReadLong(addr_p7); + aux_p4 = EEPROMReadLong(addr_p4); + aux_cal_temp = EEPROMReadLong(addr_cal_temp); + pHSensor.setCalibrationPoints(LongToFloat(aux_p10), LongToFloat(aux_p7), LongToFloat(aux_p4), LongToFloat(aux_cal_temp)); + Water.ON(); + + for (int i = 0; i < counter; i++) { + pH_val_ohm = pHSensor.readpH(); + //temp1 = readTemp(); + temp1 = readTempAuto(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(pH_val_ohm); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_p4, FloatToLong(pH_val_ohm)); + //EEPROMWriteLong(addr_p7, FloatToLong(aux_p7)); + //EEPROMWriteLong(addr_p4, FloatToLong(aux_p4)); + pHSensor.setCalibrationPoints(LongToFloat(aux_p10), LongToFloat(aux_p7), pH_val_ohm, temp1); + if (debug == 1) { + USB.println(F("Калибровка для раствора pH4 завершена.")); + } +} + +//-------------------------------------- +// Калибровка датчика окислительно-восстановительного процесса +void ORPSensorCalib() { + float orp_calib = 0.0; + float orp_calculated = 0.0; + aux_orp_offset = LongToFloat(EEPROMReadLong(addr_orp_offset)); + Water.ON(); + for (int k = 0; k < counter; k++) { + orp_calib = 1000*ORPSensor.readORP(); + // orp_calculated = orp_calib - LongToFloat(aux_orp_offset); + USB.print(F("^|")); + USB.print(k); + USB.print(F(" - ")); + USB.println(orp_calib); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + aux_orp_offset = orp_calib - 225; + EEPROMWriteLong(addr_orp_offset, FloatToLong(aux_orp_offset)); + calibration_offset = LongToFloat(EEPROMReadLong(addr_orp_offset)); + if (debug == 1) { + USB.print(F("Калибровка завершена. Значение калибровочного смещения(вольт): ")); + USB.println(aux_orp_offset); + } +} + +//-------------------------------------- +// Калибровка датчика кислорода в 100% растворе кислорода +void OxygenCalib_100p() { + aux_air_calib = EEPROMReadLong(addr_air_calib); + aux_zero_air = EEPROMReadLong(addr_zero_air); + float result = 0.0; + DOSensor.setCalibrationPoints(LongToFloat(aux_air_calib), LongToFloat(aux_zero_air)); + Water.ON(); + for (int j = 0; j < counter; j++) { + result = DOSensor.readDO(); + USB.print(F("^|")); + USB.print(j); + USB.print(F(" - ")); + USB.println(result); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_air_calib, FloatToLong(result)); + DOSensor.setCalibrationPoints(result, LongToFloat(aux_zero_air)); + if (debug == 1) { + USB.print(F("Калибровка первой точки (100) завершена.")); + } +} + +//-------------------------------------- +// Калибровка датчика кислорода в 0% растворе кислорода +void OxygenCalib_0p() { + aux_air_calib = EEPROMReadLong(addr_air_calib); + aux_zero_air = EEPROMReadLong(addr_zero_air); + float result = 0.0; + DOSensor.setCalibrationPoints(LongToFloat(aux_air_calib), LongToFloat(aux_zero_air)); + Water.ON(); + for (int j = 0; j < counter; j++) { + result = DOSensor.readDO(); + USB.print(F("^|")); + USB.print(j); + USB.print(F(" - ")); + USB.println(result); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_zero_air, FloatToLong(result)); + DOSensor.setCalibrationPoints(LongToFloat(aux_air_calib), result); + if (debug == 1) { + USB.print(F("Калибровка второй точки (0) завершена.")); + } +} + +//-------------------------------------- +// Калибровка датчика проводимости для 1-го раствора из комплекта +// Калибровочные растворы +// K = 0.1 220 uS 3000 uS +// K = 1 10500 uS 40000 uS +// K = 10 62000 uS 90000 uS +void CondCalib_R1(long rastvor1, long rastvor2) { + //aux_p1_cond = EEPROMReadLong(addr_p1_cond); + //aux_p2_cond = EEPROMReadLong(addr_p2_cond); + aux_p1_cond = rastvor1; + aux_p2_cond = rastvor2; + EEPROMWriteLong(addr_p1_cond, aux_p1_cond); + EEPROMWriteLong(addr_p2_cond, aux_p2_cond); + aux_p1 = EEPROMReadLong(addr_p1); + aux_p2 = EEPROMReadLong(addr_p2); + float resist = 0.0; + ConductivitySensor.setCalibrationPoints(aux_p1_cond, LongToFloat(aux_p1), aux_p2_cond, LongToFloat(aux_p2)); + Water.ON(); + for (int n = 0; n < counter; n++) { + resist = ConductivitySensor.readConductivity(); + USB.print(F("^|")); + USB.print(n); + USB.print(F(" - ")); + USB.println(resist); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_p1, FloatToLong(resist)); + ConductivitySensor.setCalibrationPoints(rastvor1, resist, aux_p2_cond, LongToFloat(aux_p2)); + if (debug == 1) { + USB.print(F("Раствор: ")); + USB.println(aux_p1_cond); + USB.print(F("Коэффициент: ")); + USB.println(resist); + USB.print(F("Калибровка для первого раствора завершена.")); + } +} + +//-------------------------------------- +// Калибровка датчика проводимости для 1-го раствора из комплекта +// Калибровочные растворы +// K = 0.1 220 uS 3000 uS +// K = 1 10500 uS 40000 uS +// K = 10 62000 uS 90000 uS +void CondCalib_R2(long rastvor1, long rastvor2) { + //aux_p1_cond = EEPROMReadLong(addr_p1_cond); + //aux_p2_cond = EEPROMReadLong(addr_p2_cond); + aux_p1_cond = rastvor1; + aux_p2_cond = rastvor2; + EEPROMWriteLong(addr_p1_cond, aux_p1_cond); + EEPROMWriteLong(addr_p2_cond, aux_p2_cond); + aux_p1 = EEPROMReadLong(addr_p1); + aux_p2 = EEPROMReadLong(addr_p2); + float resist = 0.0; + ConductivitySensor.setCalibrationPoints(aux_p1_cond, LongToFloat(aux_p1), aux_p2_cond, LongToFloat(aux_p2)); + Water.ON(); + for (int n = 0; n < counter; n++) { + resist = ConductivitySensor.readConductivity(); + USB.print(F("^|")); + USB.print(n); + USB.print(F(" - ")); + USB.println(resist); + delay(zadergka); + } + USB.print(F("^|finished")); + Water.OFF(); + EEPROMWriteLong(addr_p2, FloatToLong(resist)); + ConductivitySensor.setCalibrationPoints(aux_p1_cond, LongToFloat(aux_p1), rastvor2, resist); + if (debug == 1) { + USB.print(F("Раствор: ")); + USB.println(aux_p2_cond); + USB.print(F("Коэффициент: ")); + USB.println(resist); + USB.print(F("Калибровка для второго раствора завершена.")); + } +} + +void ShowSerialNumber() { + //USB.print(F("Serial ID:")); + USB.printHex(_serial_id[0]); + USB.printHex(_serial_id[1]); + USB.printHex(_serial_id[2]); + USB.printHex(_serial_id[3]); + USB.printHex(_serial_id[4]); + USB.printHex(_serial_id[5]); + USB.printHex(_serial_id[6]); + USB.printHex(_serial_id[7]); + //USB.println(); + //delay(1000); +} + +void ShowCoeff() { + cal_point_10 = LongToFloat(EEPROMReadLong(addr_p10)); + cal_point_7 = LongToFloat(EEPROMReadLong(addr_p7)); + cal_point_4 = LongToFloat(EEPROMReadLong(addr_p4)); + air_calibration = LongToFloat(EEPROMReadLong(addr_air_calib)); + zero_calibration = LongToFloat(EEPROMReadLong(addr_zero_air)); + point1_cond = EEPROMReadLong(addr_p1_cond); + point2_cond = EEPROMReadLong(addr_p2_cond); + point1_cal = LongToFloat(EEPROMReadLong(addr_p1)); + point2_cal = LongToFloat(EEPROMReadLong(addr_p2)); + cal_temp = LongToFloat(EEPROMReadLong(addr_cal_temp)); + calibration_offset = LongToFloat(EEPROMReadLong(addr_orp_offset)); + + USB.print(F("#z|10 pH-")); + USB.print(cal_point_10); + USB.print(F(",7 pH-")); + USB.print(cal_point_7); + USB.print(F(",4 pH-")); + USB.print(cal_point_4); + USB.print(F("|100%-")); + USB.print(air_calibration); + USB.print(F(",0%-")); + USB.print(zero_calibration); + USB.print(F("|")); + USB.print(point1_cond); + USB.print(F(" mkS-")); + USB.print(point1_cal); + USB.print(F(",")); + USB.print(point2_cond); + USB.print(F(" mkS-")); + USB.print(point2_cal); + USB.print(F("|")); + USB.print(cal_temp); + USB.print(F("|225 mV-")); + USB.print(calibration_offset); + USB.println(F("|")); + + + if (debug == 1) { + USB.println(F("Ph (10, 7, 4):")); + USB.println(cal_point_10); + USB.println(cal_point_7); + USB.println(cal_point_4); + USB.println(F("DO (air, zero):")); + USB.println(air_calibration); + USB.println(zero_calibration); + USB.println(F("Cond solutions:")); + USB.println(point1_cond); + USB.println(point2_cond); + USB.println(F("Cond cal points:")); + USB.println(point1_cal); + USB.println(point2_cal); + USB.println(F("Cal temp:")); + USB.println(cal_temp); + USB.println(F("ORP offset:")); + USB.println(calibration_offset); + } +} + +void SesorData() { + USB.println(F("$measure")); + Water.ON(); + Turbidity.ON(); + delay(2000); + + /////////////////////////////////////////// + // 2. Read sensors + /////////////////////////////////////////// + + // Read the ph sensor + value_pH = pHSensor.readpH(); + if (debug == 1) { + USB.print(F("Ph_volt: ")); + USB.println(value_pH); + } + // Read the temperature sensor + //value_temp = TemperatureSensor.readTemperature(); + //value_temp = Turbidity.getTemperature(); + //value_temp = readTemp(); + value_temp = readTempAuto(); + if (debug == 1) { + USB.print(F("Temp: ")); + USB.println(value_temp); + } + value_turbidity = Turbidity.getTurbidity(); + // Convert the value read with the information obtained in calibration + value_pH_calculated = pHSensor.pHConversion(value_pH,value_temp); + if (debug == 1) { + USB.print(F("Ph final: ")); + USB.println(value_pH_calculated); + } + // Reading of the ORP sensor + value_orp = 1000*ORPSensor.readORP(); + if (debug == 1) { + USB.print(F("ORP volts: ")); + USB.println(value_orp); + } + // Apply the calibration offset + value_orp_calculated = value_orp - calibration_offset; + if (debug == 1) { + USB.print(F("ORP final: ")); + USB.println(value_orp_calculated); + } + // Reading of the DI sensor + //value_di = DISensor.readDI(); + // Reading of the ORP sensor + value_do = DOSensor.readDO(); + if (debug == 1) { + USB.print(F("DO volts: ")); + USB.println(value_do); + } + // Conversion from volts into dissolved oxygen percentage + value_do_calculated = DOSensor.DOConversion(value_do); + if (debug == 1) { + USB.print(F("DO final: ")); + USB.println(value_do_calculated); + } + // Reading of the Conductivity sensor + value_cond = ConductivitySensor.readConductivity(); + if (debug == 1) { + USB.print(F("Cond before calc: ")); + USB.println(value_cond); + } + // Conversion from resistance into ms/cm + value_cond_calculated = ConductivitySensor.conductivityConversion(value_cond); + if (debug == 1) { + USB.print(F("Cond final: ")); + USB.println(value_cond_calculated); + } + + /////////////////////////////////////////// + // 3. Turn off the sensors + /////////////////////////////////////////// + + Water.OFF(); + USB.print("$w|"); + //USB.print(FloatToLong(value_temp)); + USB.print(value_temp); + USB.print("|"); + //USB.print(FloatToLong(value_pH_calculated)); + USB.print(value_pH_calculated); + USB.print("|"); + //USB.print(FloatToLong(value_cond_calculated)); + USB.print(value_cond_calculated); + USB.print("|"); + //USB.print(FloatToLong(value_do_calculated)); + USB.print(value_do_calculated); + USB.print("|"); + //USB.print(FloatToLong(value_orp_calculated)); + USB.print(value_orp_calculated); + USB.print("|"); + //USB.print(FloatToLong(value_turbidity)); + USB.print(value_turbidity); + USB.print("|"); + USB.print(PWR.getBatteryLevel(), DEC); + USB.print("|$"); + USB.println(); +} \ No newline at end of file diff --git a/firmware/water_ions_with_calibration.pde b/firmware/water_ions_with_calibration.pde new file mode 100644 index 0000000..1f51624 --- /dev/null +++ b/firmware/water_ions_with_calibration.pde @@ -0,0 +1,891 @@ +#include +#include + +//---------------------------------------------------------------------------------------- +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//ОСТАЛЬНЫЕ НАСТРОЙКИ МЕНЯТЬ ЗАПРЕЩАЕТСЯ! +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +char check_md5[] = "417e4d803cefa2397901a94089f91e21"; +char filename[] = "SWIons1_2.hex"; +char node_ID[] = "Node_02"; + +// 0 - show nothing (calibration mode) +// 1 - show frame +// 2 - show data +int ShowData = 2; + +int debug = 0; + +// Время калибровки +int counter = 100; +int zadergka = 500; + +//версия прошивки (хранится в EEPROM) +int addressFVMajor = 1025; +int addressFVMinor = 1026; +int FVMajor = 1; +int FVMinor = 2; +int auxFVMajor = 0; +int auxFVMinor = 0; + +// serial transfer vars +unsigned long timer = 0; +int command = 0; +float command_consentration = 0; + +// калибровочные точки для pH датчика +// float cal_point_10 = 1.985; +// float cal_point_7 = 2.070; +// float cal_point_4 = 2.227; +// int addr_p10 = 1030; +// int addr_p7 = 1035; +// int addr_p4 = 1039; +// long aux_p10 = 0; +// long aux_p7 = 0; +// long aux_p4 = 0; +//----------------------------------- +// Температура калибровки +float cal_temp = 23.7; +int addr_cal_temp = 1043; +long aux_cal_temp = 0; + +//calib coeffs for sensor on socket A +float A_point1_V = 0.0; +float A_point2_V = 0.0; +float A_point3_V = 0.0; +int addr_A_p1 = 1047; +int addr_A_p2 = 1051; +int addr_A_p3 = 1055; +long aux_A_p1 = 0; +long aux_A_p2 = 0; +long aux_A_p3 = 0; +float concent_A_1 = 4.0; +float concent_A_2 = 20.0; +float concent_A_3 = 40.0; +int addr_concent_A_1 = 1059; +int addr_concent_A_2 = 1063; +int addr_concent_A_3 = 1067; + +//calib coeffs for sensor on socket B +float B_point1_V = 0.0; +float B_point2_V = 0.0; +float B_point3_V = 0.0; +int addr_B_p1 = 1071; +int addr_B_p2 = 1075; +int addr_B_p3 = 1079; +long aux_B_p1 = 0; +long aux_B_p2 = 0; +long aux_B_p3 = 0; +float concent_B_1 = 132.0; +float concent_B_2 = 660.0; +float concent_B_3 = 1320.0; +int addr_concent_B_1 = 1083; +int addr_concent_B_2 = 1087; +int addr_concent_B_3 = 1091; + +//calib coeffs for sensor on socket C +float C_point1_V = 0.0; +float C_point2_V = 0.0; +float C_point3_V = 0.0; +int addr_C_p1 = 1095; +int addr_C_p2 = 1099; +int addr_C_p3 = 1103; +long aux_C_p1 = 0; +long aux_C_p2 = 0; +long aux_C_p3 = 0; +float concent_C_1 = 10.0; +float concent_C_2 = 100.0; +float concent_C_3 = 1000.0; +int addr_concent_C_1 = 1107; +int addr_concent_C_2 = 1111; +int addr_concent_C_3 = 1115; + +//calib coeffs for sensor on socket D +float D_point1_V = 0.0; +float D_point2_V = 0.0; +float D_point3_V = 0.0; +int addr_D_p1 = 1119; +int addr_D_p2 = 1123; +int addr_D_p3 = 1127; +long aux_D_p1 = 0; +long aux_D_p2 = 0; +long aux_D_p3 = 0; +float concent_D_1 = 75.0; +float concent_D_2 = 375.0; +float concent_D_3 = 750.0; +int addr_concent_D_1 = 1131; +int addr_concent_D_2 = 1135; +int addr_concent_D_3 = 1139; + +// A,B,D,C - any ion sensor +// F - pt1000 sensor +ionSensorClass SensorSocketA(SOCKET_A); // socket 1 - NH4 +ionSensorClass SensorSocketB(SOCKET_B); // socket 2 - NO3 +ionSensorClass SensorSocketC(SOCKET_C); // socket 3 - NO2 +ionSensorClass SensorSocketD(SOCKET_D); // socket 4 - Cl +pt1000Class tempSensor; + +float SOCK_A_Raw = 0.0; +float SOCK_B_Raw = 0.0; +float SOCK_C_Raw = 0.0; +float SOCK_D_Raw = 0.0; +float SOCK_A_Calc = 0.0; +float SOCK_B_Calc = 0.0; +float SOCK_C_Calc = 0.0; +float SOCK_D_Calc = 0.0; +// float value_pH = 0.0; +// float value_pH_calculated = 0.0; +float value_temp = 0.0; + + +void setup() { + USB.ON(); + SWIonsBoard.ON(); + cal_temp = LongToFloat(EEPROMReadLong(addr_cal_temp)); + // cal_point_10 = LongToFloat(EEPROMReadLong(addr_p10)); + // cal_point_7 = LongToFloat(EEPROMReadLong(addr_p7)); + // cal_point_4 = LongToFloat(EEPROMReadLong(addr_p4)); + A_point1_V = LongToFloat(EEPROMReadLong(addr_A_p1)); + A_point2_V = LongToFloat(EEPROMReadLong(addr_A_p2)); + A_point3_V = LongToFloat(EEPROMReadLong(addr_A_p3)); + concent_A_1 = LongToFloat(EEPROMReadLong(addr_concent_A_1)); + concent_A_2 = LongToFloat(EEPROMReadLong(addr_concent_A_2)); + concent_A_3 = LongToFloat(EEPROMReadLong(addr_concent_A_3)); + B_point1_V = LongToFloat(EEPROMReadLong(addr_B_p1)); + B_point2_V = LongToFloat(EEPROMReadLong(addr_B_p2)); + B_point3_V = LongToFloat(EEPROMReadLong(addr_B_p3)); + concent_B_1 = LongToFloat(EEPROMReadLong(addr_concent_B_1)); + concent_B_2 = LongToFloat(EEPROMReadLong(addr_concent_B_2)); + concent_B_3 = LongToFloat(EEPROMReadLong(addr_concent_B_3)); + C_point1_V = LongToFloat(EEPROMReadLong(addr_C_p1)); + C_point2_V = LongToFloat(EEPROMReadLong(addr_C_p2)); + C_point3_V = LongToFloat(EEPROMReadLong(addr_C_p3)); + concent_C_1 = LongToFloat(EEPROMReadLong(addr_concent_C_1)); + concent_C_2 = LongToFloat(EEPROMReadLong(addr_concent_C_2)); + concent_C_3 = LongToFloat(EEPROMReadLong(addr_concent_C_3)); + D_point1_V = LongToFloat(EEPROMReadLong(addr_D_p1)); + D_point2_V = LongToFloat(EEPROMReadLong(addr_D_p2)); + D_point3_V = LongToFloat(EEPROMReadLong(addr_D_p3)); + concent_D_1 = LongToFloat(EEPROMReadLong(addr_concent_D_1)); + concent_D_2 = LongToFloat(EEPROMReadLong(addr_concent_D_2)); + concent_D_3 = LongToFloat(EEPROMReadLong(addr_concent_D_3)); + + Utils.writeEEPROM(addressFVMajor, FVMajor); + Utils.writeEEPROM(addressFVMinor, FVMinor); + auxFVMajor = Utils.readEEPROM(addressFVMajor); + auxFVMinor = Utils.readEEPROM(addressFVMajor); + + delay(1000); + + const float concentrations_A[] = {concent_A_1, concent_A_2, concent_A_3}; + const float concentrations_B[] = {concent_B_1, concent_B_2, concent_B_3}; + const float concentrations_C[] = {concent_C_1, concent_C_2, concent_C_3}; + const float concentrations_D[] = {concent_D_1, concent_D_2, concent_D_3}; + const float voltages_A[] = {A_point1_V, A_point2_V, A_point3_V}; + const float voltages_B[] = {B_point1_V, B_point2_V, B_point3_V}; + const float voltages_C[] = {C_point1_V, C_point2_V, C_point3_V}; + const float voltages_D[] = {D_point1_V, D_point2_V, D_point3_V}; + + SensorSocketA.setCalibrationPoints(voltages_A, concentrations_A, 3); + SensorSocketB.setCalibrationPoints(voltages_B, concentrations_B, 3); + SensorSocketC.setCalibrationPoints(voltages_C, concentrations_C, 3); + SensorSocketD.setCalibrationPoints(voltages_D, concentrations_D, 3); + // pHSensor.setpHCalibrationPoints(cal_point_10, cal_point_7, cal_point_4, cal_temp); + + // frame.setID(node_ID); + // WiFi_Init(); + +} + +void loop() { + + if (ShowData == 2) { + SensorData(); + USB.flush(); + } + + // USB commands reading + timer = millis(); + while(millis()-timer < 5000) + { + if (USB.available() > 0) + { + command = USB.read(); + switch (command) { + case 65: // A + //USB.flush(); + ShowData = 0; + USB.println(F("#!")); + break; + // case 66: //B + // ShowData = 1; + // USB.println(F("#+")); + // break; + case 67: // C + ShowData = 2; + USB.println(F("#-")); + break; + case 121: // y + debug = 1; + break; + case 122: // z + ShowCoeff(); + case 100: // d + //TEMP_SENSOR_TYPE = 1; + //if (debug == 1) { USB.println(F("Temp from turbidity sensor")); } + break; + case 101: // e + //TEMP_SENSOR_TYPE = 0; + //if (debug == 1) { USB.println(F("temp from pt1000")); } + break; + case 116: // t + counter = USBGetInt(); + USB.println(F("#t")); + if (debug == 1) { USB.println(counter); } + break; + case 97: // a + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_A_Calib(command_consentration, 1); + USB.println(F("#a")); + ShowCoeff(); + break; + case 98: // b + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_A_Calib(command_consentration, 2); + USB.println(F("#b")); + ShowCoeff(); + break; + case 99: // c + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_A_Calib(command_consentration, 3); + USB.println(F("#c")); + ShowCoeff(); + break; + case 107: // k + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_B_Calib(command_consentration, 1); + USB.println(F("#k")); + ShowCoeff(); + break; + case 108: // l + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_B_Calib(command_consentration, 2); + USB.println(F("#l")); + ShowCoeff(); + break; + case 109: // m + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_B_Calib(command_consentration, 3); + USB.println(F("#m")); + ShowCoeff(); + break; + case 110: // n + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_C_Calib(command_consentration, 1); + USB.println(F("#n")); + ShowCoeff(); + break; + case 111: // o + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_C_Calib(command_consentration, 2); + USB.println(F("#0")); + ShowCoeff(); + break; + case 112: // p + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_C_Calib(command_consentration, 3); + USB.println(F("#p")); + ShowCoeff(); + break; + case 113: // q + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_D_Calib(command_consentration, 1); + USB.println(F("#q")); + ShowCoeff(); + break; + case 114: // r + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_D_Calib(command_consentration, 2); + USB.println(F("#r")); + ShowCoeff(); + break; + case 115: // s + delay(1000); + command_consentration = (float) USBGetLong(); + USB.println(F("#?")); + Socket_D_Calib(command_consentration, 3); + USB.println(F("#s")); + ShowCoeff(); + break; + case 102: // f + auxFVMajor = Utils.readEEPROM(addressFVMajor); + auxFVMinor = Utils.readEEPROM(addressFVMajor); + //USB.print(F("Имя устройства: ")); + //USB.println(node_ID); + USB.print(F("#f|")); + //delay(1000); + //USB.println(); + USB.print(node_ID); + USB.print("|"); + ShowSerialNumber(); + USB.print("|"); + //USB.print(F("Версия прошивки: ")); + USB.print(auxFVMajor); + USB.print(F(".")); + //USB.println(auxFVMinor); + USB.print(auxFVMinor); + USB.print("|"); + USB.print(check_md5); + USB.print("|"); + USB.print(filename); + USB.println(F("|")); + break; + default: + //USB.println(F("Wrong command!")); + break; + } + } + } +} + +long USBGetLong() { + char number[10]; + int i = 0; + while (USB.available() > 0) { + number[i] = (char) USB.read(); + i++; + } + + long result = atol(number); + return result; +} + +int USBGetInt() { + char number[10]; + int i = 0; + while (USB.available() > 0) { + number[i] = (char) USB.read(); + i++; + } + + int result = atoi(number); + return result; +} + +//------------------------------------------ +long FloatToLong(float val) { + long a = val * 1000; + return a; +} + +float LongToFloat(long val1) { + float b = (float) val1/1000.0; + return b; +} + +//запись в EEPROM данных типа long +void EEPROMWriteLong(int address, long value) { + byte four = (value & 0xFF); + byte three = ((value >> 8) & 0xFF); + byte two = ((value >> 16) & 0xFF); + byte one = ((value >> 24) & 0xFF); + + Utils.writeEEPROM(address, four); + Utils.writeEEPROM(address + 1, three); + Utils.writeEEPROM(address + 2, two); + Utils.writeEEPROM(address + 3, one); +} + +//чтение из EEPROM данных типа long +long EEPROMReadLong(int address1) { + long four = Utils.readEEPROM(address1); + long three = Utils.readEEPROM(address1 + 1); + long two = Utils.readEEPROM(address1 + 2); + long one = Utils.readEEPROM(address1 + 3); + + return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF); +} + +//-------------------------------------- +// калибровка датчика в сокете А, точка калибровки задается аргументом conc_temp, номер раствора задается аргументом concent_number +void Socket_A_Calib(float conc_temp, int concent_number) +{ + float volts = 0.0; + concent_A_1 = LongToFloat(EEPROMReadLong(addr_concent_A_1)); + concent_A_2 = LongToFloat(EEPROMReadLong(addr_concent_A_2)); + concent_A_3 = LongToFloat(EEPROMReadLong(addr_concent_A_3)); + float concent[] = {concent_A_1, concent_A_2, concent_A_3}; + //float temp_volts_A_Cal[] = {0.0, 0.0, 0.0}; + aux_A_p1 = EEPROMReadLong(addr_A_p1); + aux_A_p2 = EEPROMReadLong(addr_A_p2); + aux_A_p3 = EEPROMReadLong(addr_A_p3); + const float temp_volts_A[] = {LongToFloat(aux_A_p1), LongToFloat(aux_A_p2), LongToFloat(aux_A_p3)}; + SensorSocketA.setCalibrationPoints(temp_volts_A, concent, 3); + for (int i = 0; i < counter; i++) { + SWIonsBoard.ON(); + volts = SensorSocketA.read(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(volts); + SWIonsBoard.OFF(); + delay(zadergka); + } + USB.print(F("^|finished")); + if (concent_number == 1) + { + EEPROMWriteLong(addr_A_p1, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_A_1, FloatToLong(conc_temp)); + const float temp_volts_A_Cal_10[] = {volts, LongToFloat(aux_A_p2), LongToFloat(aux_A_p3)}; + const float temp_conc_A_Cal_10[] = {conc_temp, concent_A_2, concent_A_3}; + SensorSocketA.setCalibrationPoints(temp_volts_A_Cal_10, temp_conc_A_Cal_10, 3); + } + else if (concent_number == 2) + { + EEPROMWriteLong(addr_A_p2, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_A_2, FloatToLong(conc_temp)); + const float temp_volts_A_Cal_100[] = {LongToFloat(aux_A_p1), volts, LongToFloat(aux_A_p3)}; + const float temp_conc_A_Cal_100[] = {concent_A_1, conc_temp, concent_A_3}; + SensorSocketA.setCalibrationPoints(temp_volts_A_Cal_100, temp_conc_A_Cal_100, 3); + } + else if (concent_number == 3) + { + EEPROMWriteLong(addr_A_p3, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_A_3, FloatToLong(conc_temp)); + const float temp_volts_A_Cal_1000[] = {LongToFloat(aux_A_p1), LongToFloat(aux_A_p2), volts}; + const float temp_conc_A_Cal_1000[] = {concent_A_1, concent_A_2, conc_temp}; + SensorSocketA.setCalibrationPoints(temp_volts_A_Cal_1000, temp_conc_A_Cal_1000, 3); + } + else + { + //const float temp_volts_A_Cal = {volts, volts, volts};//do nothing + } + + //SensorSocketA.setCalibrationPoints(temp_volts_A_Cal, concent, 3); + if (debug == 1) { + USB.print(F("Калибровка датчика в сокете А для раствора с концентрацией ")); + USB.print(conc_temp); + USB.println(" завершена."); + } +} + +//-------------------------------------- +// калибровка датчика в сокете B, точка калибровки задается аргументом conc_temp, номер раствора задается аргументом concent_number +void Socket_B_Calib(float conc_temp, int concent_number) +{ + float volts = 0.0; + concent_B_1 = LongToFloat(EEPROMReadLong(addr_concent_B_1)); + concent_B_2 = LongToFloat(EEPROMReadLong(addr_concent_B_2)); + concent_B_3 = LongToFloat(EEPROMReadLong(addr_concent_B_3)); + float concent[] = {concent_B_1, concent_B_2, concent_B_3}; + aux_B_p1 = EEPROMReadLong(addr_B_p1); + aux_B_p2 = EEPROMReadLong(addr_B_p2); + aux_B_p3 = EEPROMReadLong(addr_B_p3); + const float temp_volts_B[] = {LongToFloat(aux_B_p1), LongToFloat(aux_B_p2), LongToFloat(aux_B_p3)}; + SensorSocketB.setCalibrationPoints(temp_volts_B, concent, 3); + for (int i = 0; i < counter; i++) { + SWIonsBoard.ON(); + volts = SensorSocketB.read(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(volts); + SWIonsBoard.OFF(); + delay(zadergka); + } + USB.print(F("^|finished")); + if (concent_number == 1) + { + EEPROMWriteLong(addr_B_p1, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_B_1, FloatToLong(conc_temp)); + const float temp_volts_B_Cal_10[] = {volts, LongToFloat(aux_B_p2), LongToFloat(aux_B_p3)}; + const float temp_conc_B_Cal_10[] = {conc_temp, concent_B_2, concent_B_3}; + SensorSocketB.setCalibrationPoints(temp_volts_B_Cal_10, temp_conc_B_Cal_10, 3); + } + else if (concent_number == 2) + { + EEPROMWriteLong(addr_B_p2, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_B_2, FloatToLong(conc_temp)); + const float temp_volts_B_Cal_100[] = {LongToFloat(aux_B_p1), volts, LongToFloat(aux_B_p3)}; + const float temp_conc_B_Cal_100[] = {concent_B_1, conc_temp, concent_B_3}; + SensorSocketB.setCalibrationPoints(temp_volts_B_Cal_100, temp_conc_B_Cal_100, 3); + } + else if (concent_number == 3) + { + EEPROMWriteLong(addr_B_p3, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_B_3, FloatToLong(conc_temp)); + const float temp_volts_B_Cal_1000[] = {LongToFloat(aux_B_p1), LongToFloat(aux_B_p2), volts}; + const float temp_conc_B_Cal_1000[] = {concent_B_1, concent_B_2, conc_temp}; + SensorSocketB.setCalibrationPoints(temp_volts_B_Cal_1000, temp_conc_B_Cal_1000, 3); + } + else + { + //const float temp_volts_B_Cal = {volts, volts, volts};//do nothing + } + + //SensorSocketA.setCalibrationPoints(temp_volts_B_Cal, concent, 3); + if (debug == 1) { + USB.print(F("Калибровка датчика в сокете B для раствора с концентрацией ")); + USB.print(conc_temp); + USB.println(" завершена."); + } +} + +//-------------------------------------- +// калибровка датчика в сокете C, точка калибровки задается аргументом conc_temp, номер раствора задается аргументом concent_number +void Socket_C_Calib(float conc_temp, int concent_number) +{ + float volts = 0.0; + concent_C_1 = LongToFloat(EEPROMReadLong(addr_concent_C_1)); + concent_C_2 = LongToFloat(EEPROMReadLong(addr_concent_C_2)); + concent_C_3 = LongToFloat(EEPROMReadLong(addr_concent_C_3)); + float concent[] = {concent_C_1, concent_C_2, concent_C_3}; + aux_C_p1 = EEPROMReadLong(addr_C_p1); + aux_C_p2 = EEPROMReadLong(addr_C_p2); + aux_C_p3 = EEPROMReadLong(addr_C_p3); + const float temp_volts_C[] = {LongToFloat(aux_C_p1), LongToFloat(aux_C_p2), LongToFloat(aux_C_p3)}; + SensorSocketC.setCalibrationPoints(temp_volts_C, concent, 3); + for (int i = 0; i < counter; i++) { + SWIonsBoard.ON(); + volts = SensorSocketC.read(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(volts); + SWIonsBoard.OFF(); + delay(zadergka); + } + USB.print(F("^|finished")); + if (concent_number == 1) + { + EEPROMWriteLong(addr_C_p1, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_C_1, FloatToLong(conc_temp)); + const float temp_volts_C_Cal_10[] = {volts, LongToFloat(aux_C_p2), LongToFloat(aux_C_p3)}; + const float temp_conc_C_Cal_10[] = {conc_temp, concent_C_2, concent_C_3}; + SensorSocketC.setCalibrationPoints(temp_volts_C_Cal_10, temp_conc_C_Cal_10, 3); + } + else if (concent_number == 2) + { + EEPROMWriteLong(addr_C_p2, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_C_2, FloatToLong(conc_temp)); + const float temp_volts_C_Cal_100[] = {LongToFloat(aux_C_p1), volts, LongToFloat(aux_C_p3)}; + const float temp_conc_C_Cal_100[] = {concent_C_1, conc_temp, concent_C_3}; + SensorSocketC.setCalibrationPoints(temp_volts_C_Cal_100, temp_conc_C_Cal_100, 3); + } + else if (concent_number == 3) + { + EEPROMWriteLong(addr_C_p3, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_C_3, FloatToLong(conc_temp)); + const float temp_volts_C_Cal_1000[] = {LongToFloat(aux_C_p1), LongToFloat(aux_C_p2), volts}; + const float temp_conc_C_Cal_1000[] = {concent_C_1, concent_C_2, conc_temp}; + SensorSocketC.setCalibrationPoints(temp_volts_C_Cal_1000, temp_conc_C_Cal_1000, 3); + } + else + { + //const float temp_volts_C_Cal = {volts, volts, volts};//do nothing + } + + //SensorSocketC.setCalibrationPoints(temp_volts_B_Cal, concent, 3); + if (debug == 1) { + USB.print(F("Калибровка датчика в сокете C для раствора с концентрацией ")); + USB.print(conc_temp); + USB.println(" завершена."); + } +} + +//-------------------------------------- +// калибровка датчика в сокете D, точка калибровки задается аргументом conc_temp, номер раствора задается аргументом concent_number +void Socket_D_Calib(float conc_temp, int concent_number) +{ + float volts = 0.0; + concent_D_1 = LongToFloat(EEPROMReadLong(addr_concent_D_1)); + concent_D_2 = LongToFloat(EEPROMReadLong(addr_concent_D_2)); + concent_D_3 = LongToFloat(EEPROMReadLong(addr_concent_D_3)); + float concent[] = {concent_D_1, concent_D_2, concent_D_3}; + aux_D_p1 = EEPROMReadLong(addr_D_p1); + aux_D_p2 = EEPROMReadLong(addr_D_p2); + aux_D_p3 = EEPROMReadLong(addr_D_p3); + const float temp_volts_D[] = {LongToFloat(aux_D_p1), LongToFloat(aux_D_p2), LongToFloat(aux_D_p3)}; + SensorSocketD.setCalibrationPoints(temp_volts_D, concent, 3); + for (int i = 0; i < counter; i++) { + SWIonsBoard.ON(); + volts = SensorSocketD.read(); + USB.print(F("^|")); + USB.print(i); + USB.print(F(" - ")); + USB.println(volts); + SWIonsBoard.OFF(); + delay(zadergka); + } + USB.print(F("^|finished")); + if (concent_number == 1) + { + EEPROMWriteLong(addr_D_p1, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_D_1, FloatToLong(conc_temp)); + const float temp_volts_D_Cal_10[] = {volts, LongToFloat(aux_D_p2), LongToFloat(aux_D_p3)}; + const float temp_conc_D_Cal_10[] = {conc_temp, concent_D_2, concent_D_3}; + SensorSocketD.setCalibrationPoints(temp_volts_D_Cal_10, temp_conc_D_Cal_10, 3); + } + else if (concent_number == 2) + { + EEPROMWriteLong(addr_D_p2, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_D_2, FloatToLong(conc_temp)); + const float temp_volts_D_Cal_100[] = {LongToFloat(aux_D_p1), volts, LongToFloat(aux_D_p3)}; + const float temp_conc_D_Cal_100[] = {concent_D_1, conc_temp, concent_D_3}; + SensorSocketD.setCalibrationPoints(temp_volts_D_Cal_100, temp_conc_D_Cal_100, 3); + } + else if (concent_number == 3) + { + EEPROMWriteLong(addr_D_p3, FloatToLong(volts)); + EEPROMWriteLong(addr_concent_D_3, FloatToLong(conc_temp)); + const float temp_volts_D_Cal_1000[] = {LongToFloat(aux_D_p1), LongToFloat(aux_D_p2), volts}; + const float temp_conc_D_Cal_1000[] = {concent_D_1, concent_D_2, conc_temp}; + SensorSocketD.setCalibrationPoints(temp_volts_D_Cal_1000, temp_conc_D_Cal_1000, 3); + } + else + { + //const float temp_volts_C_Cal = {volts, volts, volts};//do nothing + } + + //SensorSocketC.setCalibrationPoints(temp_volts_B_Cal, concent, 3); + if (debug == 1) { + USB.print(F("Калибровка датчика в сокете D для раствора с концентрацией ")); + USB.print(conc_temp); + USB.println(" завершена."); + } +} + +void ShowSerialNumber() { + //USB.print(F("Serial ID:")); + USB.printHex(_serial_id[0]); + USB.printHex(_serial_id[1]); + USB.printHex(_serial_id[2]); + USB.printHex(_serial_id[3]); + USB.printHex(_serial_id[4]); + USB.printHex(_serial_id[5]); + USB.printHex(_serial_id[6]); + USB.printHex(_serial_id[7]); + //USB.println(); + //delay(1000); +} + +void ShowCoeff() { + cal_temp = LongToFloat(EEPROMReadLong(addr_cal_temp)); +// cal_point_10 = LongToFloat(EEPROMReadLong(addr_p10)); +// cal_point_7 = LongToFloat(EEPROMReadLong(addr_p7)); +// cal_point_4 = LongToFloat(EEPROMReadLong(addr_p4)); + A_point1_V = LongToFloat(EEPROMReadLong(addr_A_p1)); + A_point2_V = LongToFloat(EEPROMReadLong(addr_A_p2)); + A_point3_V = LongToFloat(EEPROMReadLong(addr_A_p3)); + concent_A_1 = LongToFloat(EEPROMReadLong(addr_concent_A_1)); + concent_A_2 = LongToFloat(EEPROMReadLong(addr_concent_A_2)); + concent_A_3 = LongToFloat(EEPROMReadLong(addr_concent_A_3)); + B_point1_V = LongToFloat(EEPROMReadLong(addr_B_p1)); + B_point2_V = LongToFloat(EEPROMReadLong(addr_B_p2)); + B_point3_V = LongToFloat(EEPROMReadLong(addr_B_p3)); + concent_B_1 = LongToFloat(EEPROMReadLong(addr_concent_B_1)); + concent_B_2 = LongToFloat(EEPROMReadLong(addr_concent_B_2)); + concent_B_3 = LongToFloat(EEPROMReadLong(addr_concent_B_3)); + C_point1_V = LongToFloat(EEPROMReadLong(addr_C_p1)); + C_point2_V = LongToFloat(EEPROMReadLong(addr_C_p2)); + C_point3_V = LongToFloat(EEPROMReadLong(addr_C_p3)); + concent_C_1 = LongToFloat(EEPROMReadLong(addr_concent_C_1)); + concent_C_2 = LongToFloat(EEPROMReadLong(addr_concent_C_2)); + concent_C_3 = LongToFloat(EEPROMReadLong(addr_concent_C_3)); + D_point1_V = LongToFloat(EEPROMReadLong(addr_D_p1)); + D_point2_V = LongToFloat(EEPROMReadLong(addr_D_p2)); + D_point3_V = LongToFloat(EEPROMReadLong(addr_D_p3)); + concent_D_1 = LongToFloat(EEPROMReadLong(addr_concent_D_1)); + concent_D_2 = LongToFloat(EEPROMReadLong(addr_concent_D_2)); + concent_D_3 = LongToFloat(EEPROMReadLong(addr_concent_D_3)); + + USB.print(F("#z|")); + USB.print(concent_A_1); + USB.print(F(" mg/L-")); + USB.print(A_point1_V); + USB.print(F(",")); + USB.print(concent_A_2); + USB.print(F(" mg/L-")); + USB.print(A_point2_V); + USB.print(F(",")); + USB.print(concent_A_3); + USB.print(F(" mg/L-")); + USB.print(A_point3_V); + USB.print(F("|")); + USB.print(concent_B_1); + USB.print(F(" mg/L-")); + USB.print(B_point1_V); + USB.print(F(",")); + USB.print(concent_B_2); + USB.print(F(" mg/L-")); + USB.print(B_point2_V); + USB.print(F(",")); + USB.print(concent_B_3); + USB.print(F(" mg/L-")); + USB.print(B_point3_V); + USB.print(F("|")); + USB.print(concent_C_1); + USB.print(F(" mg/L-")); + USB.print(C_point1_V); + USB.print(F(",")); + USB.print(concent_C_2); + USB.print(F(" mg/L-")); + USB.print(C_point2_V); + USB.print(F(",")); + USB.print(concent_C_3); + USB.print(F(" mg/L-")); + USB.print(C_point3_V); + USB.print(F("|")); + USB.print(concent_D_1); + USB.print(F(" mg/L-")); + USB.print(D_point1_V); + USB.print(F(",")); + USB.print(concent_D_2); + USB.print(F(" mg/L-")); + USB.print(D_point2_V); + USB.print(F(",")); + USB.print(concent_D_3); + USB.print(F(" mg/L-")); + USB.print(D_point3_V); + USB.print(F("|")); + USB.print(cal_temp); + USB.println(F("|")); + +// USB.println(cal_point_10); +// USB.println(cal_point_7); +// USB.println(cal_point_4); + if (debug == 1) { + USB.println(F("NH4: concent - volts")); + USB.print(concent_A_1); + USB.print(F(" - ")); + USB.println(A_point1_V); + USB.print(concent_A_2); + USB.print(F(" - ")); + USB.println(A_point2_V); + USB.print(concent_A_3); + USB.print(F(" - ")); + USB.println(A_point3_V); + USB.println(F("NO3: concent - volts")); + USB.print(concent_B_1); + USB.print(F(" - ")); + USB.println(B_point1_V); + USB.print(concent_B_2); + USB.print(F(" - ")); + USB.println(B_point2_V); + USB.print(concent_B_3); + USB.print(F(" - ")); + USB.println(B_point3_V); + USB.println(F("NO2: concent - volts")); + USB.print(concent_C_1); + USB.print(F(" - ")); + USB.println(C_point1_V); + USB.print(concent_C_2); + USB.print(F(" - ")); + USB.println(C_point2_V); + USB.print(concent_C_3); + USB.print(F(" - ")); + USB.println(C_point3_V); + USB.println(F("Cl: concent - volts")); + USB.print(concent_D_1); + USB.print(F(" - ")); + USB.println(D_point1_V); + USB.print(concent_D_2); + USB.print(F(" - ")); + USB.println(D_point2_V); + USB.print(concent_D_3); + USB.print(F(" - ")); + USB.println(D_point3_V); + USB.println(F("temp: concent - volts")); + USB.println(cal_temp); + } +} + +void SensorData() { + USB.println(F("$measure")); + SWIonsBoard.ON(); + //delay(2000); + /////////////////////////////////////////// + // 2. Read sensors + /////////////////////////////////////////// + value_temp = tempSensor.read(); + // value_pH = pHSensor.read(); + // value_pH_calculated = pHSensor.pHConversion(value_pH, value_temp); + // delay(500); + SOCK_A_Raw = SensorSocketA.read(); + SOCK_A_Calc = SensorSocketA.calculateConcentration(SOCK_A_Raw); + if (debug == 1) { + USB.print(F("NH4 volts: ")); + USB.print(SOCK_A_Raw); + USB.print(F(", value: ")); + USB.println(SOCK_A_Calc); + } + delay(1500); + SOCK_B_Raw = SensorSocketB.read(); + SOCK_B_Calc = SensorSocketB.calculateConcentration(SOCK_B_Raw); + if (debug == 1) { + USB.print(F("NO3 volts: ")); + USB.print(SOCK_B_Raw); + USB.print(F(", value: ")); + USB.println(SOCK_B_Calc); + } + delay(1500); + SOCK_C_Raw = SensorSocketC.read(); + SOCK_C_Calc = SensorSocketC.calculateConcentration(SOCK_C_Raw); + if (debug == 1) { + USB.print(F("NO2 volts: ")); + USB.print(SOCK_C_Raw); + USB.print(F(", value: ")); + USB.println(SOCK_C_Calc); + } + delay(1500); + SOCK_D_Raw = SensorSocketD.read(); + SOCK_D_Calc = SensorSocketD.calculateConcentration(SOCK_D_Raw); + if (debug == 1) { + USB.print(F("Cl volts: ")); + USB.print(SOCK_D_Raw); + USB.print(F(", value: ")); + USB.println(SOCK_D_Calc); + } + delay(500); + /////////////////////////////////////////// + // 3. Turn off the sensors + /////////////////////////////////////////// + SWIonsBoard.OFF(); + + USB.print("$i|"); + USB.print(value_temp); + USB.print("|"); + USB.print(SOCK_A_Calc); + USB.print("|"); + USB.print(SOCK_B_Calc); + USB.print("|"); + USB.print(SOCK_C_Calc); + USB.print("|"); + USB.print(SOCK_D_Calc); + USB.print("|"); + USB.print(PWR.getBatteryLevel(), DEC); + USB.print("|$"); + USB.println(); +}