Предисловие:
История нашей маленькой телекомпании тянется аж от 1992 года. И чего в ней только не было. Например, до 2012, в ней не было ни одного серверного помещения. Но времена менялись и серверы всё же понадобились, как и помещение под них. Про то, как я строил серверную, мы еще поговорим. А пока уделим внимание одной маленькой её детали – кондиционированию. Дело в том, что при тогдашнем ограниченном бюджете, мы ставили обычные бытовые кондиционеры. И что бы парочка «домашних парней» не офигела раньше времени от работы 24/7, применялась адская машинка под названием «Блок ротации»:
Его задача была проста: каждые N-цать часов переключать кондиционеры один на другой, что бы они поочередно отдыхали, а если запахнет жареным станет жарко, пробудить спящего брата на подмогу. Стоил он в районе 15-20 тысяч рублей и производился несколькими фирмами специально для таких вот малых предприятий, которые не могли себе позволить дорогие «канальники» или подобное, со встроенными системами ротации. Надо сказать, что шайтан-коробка работала исправно и не сбоила до определенного момента. Но, отработав 7 лет и пережив пару кондиционеров, она всё же решила щелкнуть ластами (с чего бы это?), а заодно едва не прихватила кондиционеры с собой. Но обо всём по порядку.
Глава 1 «Внимание! Температура в серверной высокая.»
Вот с такой СМСки и начался у меня обед однажды. Ну, думаю, поел блин! Спускаемся с сисадмином в серверную и видим, как этот кусок российской идеи блок ротации поехал кукухой и весело (видимо уже около получаса) включает и выключает оба кондиционера со скоростью фрикций старой беременной путаны. Мы переглянулись с админом, выключили ротатор, кондиционеры весело ожили и начали сражаться кто кого передует. Ну что же, делать нечего, сняли «приехавшего» с DIN-рейки и понесли вскрывать. На лабораторном столе, подключив все датчики и прочее, решили начать диагностику с запуска. И о чудо! Этот жуликоватый приборчик встал в штатный режим, и как ни в чем не бывало, продолжил свой обычный трудовой день. Но нас так просто не проведёшь. Решили оставить его на стенде на сутки… и не зря. На утро, когда я открыл свой кабинет, пациент снова весело щелкал релюшками, как умалишённый. Вердикт однозначный – препарирование. И вот тут Остапа понесло меня посетил «я ж инженер».
Дело в том, что как раз на кануне мы закончили запуск нового комплекса, а он включал в себя и систему диспетчеризации. Эта система присматривала за всем комплексом по температуре, влажности, напряжениям, частотам и т.д. переключала новые мощные кондиционеры по времени и, если что-то ей не нравилось, она присылала нам СМС. Как раз вроде того, что обломало мне обед. Разработка эта чешской компании Conteg. Она строилась на базе собственных контроллеров RAMOS и была не то что бы без глюков, но если руки прямые, то вполне адекватная. И так как термометр ramos мы уже поставили в серверную, меня посетила мысль с дружеским визитом: а почему бы не продолжить внедрение и не подружить управление старыми кондиционерами с данной новой диспетчеризацией?
Глава 2 «рождение ТЗ»
Начнём с возможностей контроллера ramos. Из того что он может нам нужно только переключение по времени и переключение по температуре. В сущности, всё то же самое что умел наш ротатор до того, как обезумел. Но теперь мы сможем это видеть на мониторе и управлять расписанием с компьютера:
Значит нам нужно создать некое подобие адаптера «кондиционер – диспетчеризация». За основу как логики, так и схемотехники возьмём тот же ротатор. Т.е. наше устройство должно уметь:
- Определять наличие напряжений на кондиционерах и реагировать на аварии по питанию.
- Реагировать на сигналы типа «сухой контакт» от диспетчеризации: ченьджовер (переключение по времени) и термостат (переключение по температуре).
- Переключать кондиционеры с паузой, чтобы дать время на запуск одного перед выключением другого.
- Сообщать системе ramos о том, что происходит в реальном времени.
- (то чего не хватало ротатору) Не плохо было бы иметь кнопку экстренной остановки кондиционеров. На всякий аварийный случай.
Исходя из вышеперечисленного, как смог, нарисовал блок – схему:
Глава 3 «и снова богомерзкая Arduino»
Да, да, я могу сколько угодно ругать ардуину, но её простота перекрывает всё, что я бы не высказал о ней. Так что ёжики кололись, икали, плакали, но продолжали жрать кактус кодить на ардуине. Поразмыслив над ТЗ, накидал схему:
Трансформатор выдрал из препарированного безумца, он выдавал 12в после выпрямления, что нам и нужно. Оптроны PC814 тоже оттуда. Их задача следить за переменным напряжением кондиционеров. А вот резисторы R2 и R6 я взял по мощнее. По-хорошему вообще одноваттные нужны, потому что даже полуваттные грелись прилично. Реле управления кондиционерами соединял так же, как и в старом ротаторе: на нормально замкнутый контакт. Это сделано для того, чтобы при отключении прибора, он не выключал всё охлаждение. Такой себе режим Bypass. ULN2003 применена, просто потому, что была под рукой. Как и реле обратной связи MD-5. Можно вместо них применять и обычные реле через ту же сборку дарлингтона, суть от этого не изменится. Ну и конечно нужно немного покодить:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
#define CHANGEOVER A0 #define T_ALARM A1 #define P_SENSOR_1 A4 #define P_SENSOR_2 A5 #define C_RELAY_1 3 #define C_RELAY_2 2 #define D_RELAY_1 12 #define D_RELAY_2 13 #define LED_HARDBEAT 10 #define EMERGENCY 11 #define SPK 9 unsigned long currentMillis = 0; //текущее время unsigned long previousMillis = 0; //предыдущее время unsigned long hardbeatMillis = 0; //время индикатора const unsigned int delayMillis = 10000; //время задержки bool ledState = LOW; bool emergencyState = LOW; bool L1; bool L2; bool Alarm; bool ChangeOver; void varLoop() //опрос датчиков { int valL1 = analogRead(P_SENSOR_1); int valL2 = analogRead(P_SENSOR_2); if (valL1 != 1023) L1 = HIGH; else L1 = LOW; if (valL2 != 1023) L2 = HIGH; else L2 = LOW; Alarm = digitalRead(T_ALARM); //ChangeOver = digitalRead(CHANGEOVER); } void hardbeatLoop(unsigned int pulse) //индикатор работы { if (currentMillis - hardbeatMillis >= pulse) { hardbeatMillis = currentMillis; ledState = !ledState; digitalWrite(LED_HARDBEAT, ledState); } } void emergencyLoop() //цикл экстреной остановки { if (digitalRead(EMERGENCY) == LOW)emergencyState = HIGH; if (emergencyState) { digitalWrite(C_RELAY_1, HIGH); digitalWrite(C_RELAY_2, HIGH); digitalWrite(D_RELAY_1, HIGH); digitalWrite(D_RELAY_2, HIGH); hardbeatLoop(1); tone(SPK, 4000, 200); delay(300); } } void mainLoop() //осноной цикл работы { hardbeatLoop(1000); if (L1 && L2 && Alarm) { if (digitalRead(CHANGEOVER) != ChangeOver); { if (digitalRead(CHANGEOVER)) { if (currentMillis - previousMillis >= delayMillis) { digitalWrite(C_RELAY_1, LOW); digitalWrite(D_RELAY_1, LOW); } if (currentMillis - previousMillis >= delayMillis * 2) { previousMillis = currentMillis; digitalWrite(C_RELAY_2, HIGH); digitalWrite(D_RELAY_2, HIGH); } } else { if (currentMillis - previousMillis >= delayMillis) { digitalWrite(C_RELAY_2, LOW); digitalWrite(D_RELAY_2, LOW); } if (currentMillis - previousMillis >= delayMillis * 2) { previousMillis = currentMillis; digitalWrite(C_RELAY_1, HIGH); digitalWrite(D_RELAY_1, HIGH); } } ChangeOver = digitalRead(CHANGEOVER); } } else { digitalWrite(D_RELAY_1, !L1); digitalWrite(D_RELAY_2, !L2); if (!L1)digitalWrite(C_RELAY_2, LOW); if (!L2)digitalWrite(C_RELAY_1, LOW); } } void setup() { pinMode(CHANGEOVER, INPUT_PULLUP); pinMode(T_ALARM, INPUT_PULLUP); pinMode(EMERGENCY, INPUT_PULLUP); pinMode(P_SENSOR_1, INPUT); pinMode(P_SENSOR_2, INPUT); pinMode(C_RELAY_1, OUTPUT); pinMode(C_RELAY_2, OUTPUT); pinMode(D_RELAY_1, OUTPUT); pinMode(D_RELAY_2, OUTPUT); pinMode(LED_HARDBEAT, OUTPUT); pinMode(SPK, OUTPUT); //"hello" beep tone(SPK, 3000, 200); delay(150); tone(SPK, 3500, 200); delay(150); tone(SPK, 4000, 200); // } void loop() { currentMillis = millis(); //основное время varLoop(); emergencyLoop(); if (!emergencyState) mainLoop(); //delay (1000); } |
Как видно в коде, сразу отказываемся от не православных «Delay()». Используем их только в emergencyLoop(). Потому, что если мы упали в emergencyLoop(), то это конечная. Далее только перезапуск питания или reset контроллеру. Зачем? Объясню ниже.
Комментариев в коде почти нет (да и код кривой если честно), уж простите, я не программист. Я быдло-кодер. Главное что работает и так как нужно.
Глава 3 «Разум рождён, пора и тело взрастить»
Отладив все свои хотелки на симуляторе, переходим к хардвару. Плата у меня получилась вот такая:
Размеры платы и расположение разъемов и прочего, я так же подгонял под корпус обезумевшего ротатора. Ардуину, я как настоящий ардусатанист – некромант, поставил самым любимым для меня способом. Т.е. вывернул на изнанку. Главное, когда делаешь подобные платы, где встречаются 220 вольт и слаботочка, соблюдать все меры предосторожности. Тут и разносить эти части нужно подальше, и развязывать оптронами, и вообще плату крайне желательно после сборки залить лаком. Вот что получилось у меня:
При подключении всех этих пирогов тоже важно соблюдать очередность и полярность. Фаза и ноль должны быть строго на своих клеммах, иначе логика нормально не заработает.
Заключение “it’s alive!”
По итогу, настроив пару входов (SRV_conditioner_1 и SRV_conditioner_2) и пару выходов (SRV_changeover и SRV_Alarm_Temp) в контроллере Ramos, мы получили на выходе действующую систему. Описывать подробно настройку диспетчеризации смысла нет, у каждого свои методы и система может быть не только Ramos, а любая аналогичная. Ключевой момент: нужно 2 входа и 2 выхода типа “сухой контакт”.
Логика следующая:
Если питания на устройстве нет, то оба кондиционера включены, но обратная связь говорит ramos’у, что SRV_conditioner_1 и SRV_conditioner_2 выключены и это условно «авария». При подаче питания, устройство проверяет, какой кондиционер хочет включить ramos а какой отправить в спячку, ждёт указаное в прошивке время (10-20 секунд) и выполняет пожелания ramos’а, не забыв ему ответить какой именно спит, а какой работает. Так же на корпусе светодиод «hardBeat» начинает мигать, как бы говоря нам, что он работает и думу думает, а не висит и вот это вот всё. Если питание одного из кондиционеров выключено или ramos сообщает о высокой температуре (замыкает контакт SRV_Alarm_Temp), то устройство включает все доступные кондиционеры, до момента, пока аварию не устранят. В свою очередь ramos настроен так, чтобы каждые 16 часов давать команду на переключение кондиционера, переключив контакт SRV_changeover. И, как вишенка на торте безумия, кнопка «Экстренная остановка». Если её нажать, все кондиционеры отключатся, блок сообщает ramos’у, что всё отключено и начинает пищать и мигать, как умалишённый. Из этого режима прибор уже не выйдет до перезапуска питания. Это сделано на всякий экстренный случай. И если он настал, то мы должны быть уверены, что прибор не включит кондиционеры ни при каких обстоятельствах.
Это я всё к чему: пользуйтесь своими мозгами правильно.