- •Выпускная квалификационная работа на соискание академической степени бакалавра
- •Березники 2016
- •Задание на выполнение выпускной работы бакалавра
- •Аннотация
- •Введение. Предметная область
- •Функциональная спецификация
- •Спецификация качества
- •Функциональное моделирование предметной области
- •Информационное моделирование предметной области
- •Логическая модель
- •Физическая модель
- •Проектирование информационной системы
- •Выбор аппаратных средств реализации
- •Выбор программных средств реализации
- •Выбор модели жизненного цикла системы
- •Разработка информационной системы
- •Документация ис
- •Руководство пользования веб-интерфейсом
- •Заключение
- •Список литературы
Выбор модели жизненного цикла системы
Для разработки системы выбрана спиральная модель жизненного цикла. Этот выбор обоснован новаторским характером разработки и связанной с ним необходимостью раннего прототипирования, а также требованием лёгкости модификации системы. В цикле можно выделить следующие этапы:
Сбор и анализ материалов для проектирования.
Проектирование информационной системы.
Проектирование устройства мониторинга температуры и создание действующего прототипа.
Тестирование устройства.
Проектирование веб-составляющей системы, её разработка, внесение корректив.
Тестирование веб-составляющей.
После завершения тестирования на первой и последующих итерациях вносятся коррективы в требования к устройству и серверу, и работа возобновляется с третьего этапа.
Разработка информационной системы
Рассмотрим некоторые моменты создания системы:
Разработка прототипа устройства мониторинга и прошивки для него.
После создания принципиальной электрической схемы устройства и её воплощения на макетной плате была начата работа над прошивкой. Листинг готовой прошивки представлен ниже.
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#define ONE_WIRE_BUS 12
#define STARTUP_DELAY 10000
#define STANDARD_DELAY 1000
#define DELIM "@"
const String getTime = "AT+CCLK?";
const String getOperator = "AT+CSPN?";
const String getIME = "AT+CGSN";
String imei = "";
String mobop = "";
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress thermometer1;
DeviceAddress thermometer2;
SoftwareSerial GSMport(8, 7); // RX, TX
unsigned long previousMillis = 0;
const long interval = 60000;
void initGSM() {
String apn = "";
String user = "";
String pwd = "";
String cont = "";
if (mobop.indexOf("MTS") > -1) {
apn = "internet.mts.ru";
user = "mts";
pwd = "mts";
cont = "internet.mts.ru";
} else if (mobop.indexOf("BEELINE") > -1) {
apn = "internet.beeline.ru";
user = "beeline";
pwd = "beeline";
cont = "internet.beeline.ru";
} else if (mobop.indexOf("MEGAFON") > -1) {
apn = "internet";
user = "megafon";
pwd = "megafon";
cont = "internet";
} else if (mobop.indexOf("TELE2") > -1) {
apn = "internet.TELE2.ru";
user = "";
pwd = "";
cont = "internet.tele2.ru";
}
execCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", STANDARD_DELAY * 4);
execCommand("AT+SAPBR=3,1,\"APN\",\"" + apn + "\"", STANDARD_DELAY);
execCommand("AT+SAPBR=3,1,\"USER\",\"" + user + "\"", STANDARD_DELAY);
execCommand("AT+SAPBR=3,1,\"PWD\",\"" + pwd + "\"", STANDARD_DELAY);
execCommand("AT+CGDCONT=1,\"IP\",\"" + cont + "\"", STANDARD_DELAY);
}
void gprs_send(String data) {
initGSM();
execCommand("AT+SAPBR=1,1", STANDARD_DELAY * 2);
execCommand("AT+HTTPINIT", STANDARD_DELAY);
execCommand("AT+HTTPPARA=\"CID\",1", STANDARD_DELAY);
execCommand("AT+HTTPPARA=\"URL\",\"http://vps3908.vps.host.ru/recieveReadings.php\"", STANDARD_DELAY * 2);
execCommand("AT+HTTPPARA=\"CONTENT\",\"application/x-www-form-urlencoded\"", STANDARD_DELAY);
execCommand("AT+HTTPDATA=" + String(data.length()) + ",10000", STANDARD_DELAY*2);
execCommand(data, STANDARD_DELAY*3);
execCommand("AT+HTTPACTION=1", STANDARD_DELAY*5);
execCommand("AT+HTTPTERM", STANDARD_DELAY * 2);
execCommand("AT+SAPBR=0,1", STANDARD_DELAY * 2);
}
String ReadGSM(void) {
int c;
String v;
while (GSMport.available()) {
c = GSMport.read();
v += char(c);
delay(10);
}
return v;
}
void initTemps(void) {
sensors.begin();
sensors.getAddress(thermometer1, 0);
sensors.getAddress(thermometer2, 1);
sensors.setResolution(thermometer1, 10);
sensors.setResolution(thermometer2, 10);
}
void sendTemps(void) {
sensors.requestTemperatures();
float t1 = sensors.getTempC(thermometer1);
Serial.println(t1);
float t2 = sensors.getTempC(thermometer2);
Serial.println(t2);
String toSend = formHeader() + DELIM + String(t1) + DELIM + String(t2);
gprs_send(toSend);
}
String execCommand(String comm, int d) {
Serial.println("Flushed: " + ReadGSM());
GSMport.println(comm);
delay(d);
String response = ReadGSM();
Serial.println(response);
return response;
}
String formHeader() {
String uptime = execCommand(getTime, STANDARD_DELAY);
uptime.replace("+CCLK:", "");
uptime.replace(getTime, "");
cleanStr(uptime);
return "t1=" + imei + DELIM + uptime;
}
void cleanStr(String & str) {
str.replace("OK", "");
str.replace("\"", "");
str.replace("\n", "");
str.replace("\r", "");
str.trim();
}
void setup(void)
{
delay(STARTUP_DELAY);
Serial.begin(9600);
GSMport.begin(9600);
execCommand("AT", STANDARD_DELAY * 5);
mobop = execCommand(getOperator, STANDARD_DELAY * 3);
mobop.replace("+CSPN:", "");
mobop.replace(getOperator, "");
cleanStr(mobop);
mobop.toUpperCase();
imei = execCommand(getIME, STANDARD_DELAY * 3);
imei.replace(getIME, "");
cleanStr(imei);
Serial.println("Operator " + mobop);
Serial.println("IMEI " + imei);
initTemps();
}
void loop(void)
{
if (GSMport.available())
Serial.write(GSMport.read());
if (Serial.available())
GSMport.write(Serial.read());
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
previousMillis = currentMillis;
sendTemps();
}
}
Функция setup выполняется однократно при запуске контроллера, она обеспечивает инициализацию серийных портов для связи контроллера с GSM-модулем и отладки, проверяет состояния модуля, отправив на него команду «AT», выясняет оператора мобильной связи и устанавливает глобальные переменные с настройками подключения в значения, соответствующие используемому оператору.
Надо заметить, что взаимодействие контроллера с GSM-модулем происходит через последовательный интерфейс с помощью так называемых AT-команд [8]. Для облегчения отправки этих команд модулю написана специальная оборачивающая функция execCommand.
После завершения функции setup контроллер входит в циклический режим и бесконечно выполняет функцию loop. В её теле находится проверка, прошло ли достаточно времени для следующей отправки показаний, чтение температур с датчиков, формирование и отправка запроса на сервер. Запрос представляет из себя обычный POST-запрос с одним параметром, содержащим через разделитель @ все необходимые данные: IMEI устройства, время его функционирования без перезагрузки, и сами показания температуры.
Создание готового устройства.
После тестирования прошивки и отправки тестовых запросов прототипом устройство было переведено на финальную аппаратную базу. Для этого во fritzing (Рис. 13) была спроектирована печатная плата, на которой размещаются все элементы, затем её трафарет распечатан на лазерном принтере, переведён на текстолит и вытравлен с помощью хлорного железа.
Рис. 13 Схема печатной платы во fritzing
Затем все компоненты были распаяны на печатной плате, а на контроллер залита прошивка. Готовое устройство изображено на Рис. 14. После этого устройство было помещено в корпус и подверглось тестированию надёжности. В течение суток оно было подключено к сети, отправляемые данные регистрировались сервером. Ошибок при отправке и приёме данных обнаружено не было, устройство и систему приёма данных сервера можно считать надёжными.
Рис. 14 Готовое устройство без корпуса
Разработка веб-сервера.
Веб-сервер использует AngularJS и websocket для асинхронного получения данных без перезагрузки страницы (Рис. 15). Для отображения температурных данных в виде графиков используется библиотека highcharts, которая также позволяет динамически обновлять графики.
Рис. 15 Вкладка с показаниями датчиков
При открытии страницы в браузере осуществляется соединение с сервером через сокет, и в дальнейшем состояние страницы в браузере синхронизируется с состоянием сервера при любом его изменении с помощью разработанной системы сообщений(Рис. 16). За счёт этого можно наблюдать приходящие на сервер температурные данные в реальном времени, добавлять, редактировать и удалять устройства, датчики и пользователей и получать уведомления об ошибках сервера без перезагрузки страницы.
Рис. 16 Сокет-события клиента
