Cценарий осуществляет управление фреоновым охладителем с несколькими ступенями (в данном случае 3), обеспечивая регулирование температуры в помещении и ротацию ступеней для равномерного распределения нагрузки.

Скриншот панели управления Скриншот панели управления

Алгоритм

Алгоритм работает следующим образом:

  1. Инициализация:

    • Создаются объекты для каждой ступени охладителя (FreonCooler), с привязкой к цифровым выходам (Do) и регистрам для учета времени работы.
    • Настраиваются параметры: заданная температура (rSetTemp), гистерезис (rHysteresis), время ротации (rRotationTime), задержка переключений (rDelay).
  2. Основной цикл (выполняется каждую секунду):

    • Проверка питания: Если питание (rPower) выключено, все ступени отключаются.
    • Обработка задержки: Если счетчик задержки (rCounter) больше 0, он уменьшается, и дальнейшая логика приостанавливается.
    • Сбор данных:
      • Обновляется время работы (timeOn) и простоя (timeOff) для каждой ступени.
      • Определяются ступень с максимальным временем работы (freonOnMax) и максимальным простоем (freonOffMax).
    • Регулирование температуры:
      • Если температура (aiTemp) превышает верхний порог (rSetTemp + rHysteresis) и не все ступени включены, включается ступень с максимальным простоем.
      • Если температура ниже нижнего порога (rSetTemp - rHysteresis) и есть включенные ступени, выключается ступень с максимальным временем работы.
    • Ротация по времени: Если время работы включенной ступени превышает заданное время ротации (rRotationTime), она выключается, а включается ступень с максимальным простоем.
    • После каждого переключения устанавливается задержка (rDelay), чтобы избежать частых включений/выключений.
  3. Логирование: Изменения состояния ступеней (вкл/выкл) сопровождаются выводом причины (например, “temp” или “rotation”).

Возможности

  • Регулирование температуры: Поддерживает заданную температуру с учетом гистерезиса.
  • Ротация ступеней: Обеспечивает равномерную нагрузку на оборудование, продлевая срок службы.
  • Контроль времени работы: Ведет учет наработки каждой ступени в минутах.
  • Гибкая настройка: Позволяет задавать температуру, гистерезис, время ротации и задержку через веб-интерфейс.
  • Мониторинг: Данные о температуре и состоянии ступеней доступны через веб-панель.

Область применения

Сценарий подходит для автоматизации систем охлаждения, где требуется:

  • Климат-контроль: Управление температурой в помещениях (склады, серверные, офисы).
  • Промышленное охлаждение: Работа с многоступенчатыми фреоновыми системами на производстве.
  • Энергоэффективность: Оптимизация использования ресурсов за счет ротации оборудования.
  • IoT-интеграция: Мониторинг и управление через веб-интерфейс в умных системах.

Производительность

Замеры осуществлялись на тестовом образце

Время компиляции 136 мс
Среднее время выполнения тела цикла <1 мс
Использование стека 640 байт (7.8%)
Использование кучи 3968 байт (6.5%)

Сценарий

  '''
Управление фреоновым охладителем с несколькими ступенями.
Ротация ступеней.
'''

from dev import Ai, Do, Reg, Alarm, Event, webconf, run, count

class FreonCooler:
    '''
    Класс, представляющий одну ступень фреонового охладителя.
    '''
    def __init__(self, num, doPin, reg):
        self.num = num
        # Цифровой выход, управляющий ступенью
        self.doPower = doPin.conf(name=f'Ступень {num}', access='r')
        # Регистр для подсчета наработки в минутах
        self.reg = reg.conf(name=f'Наработка {num}, мин.', type='uint', default=0, access='rr')
        self.timeOn = 0     # Время работы ступени в секундах
        self.timeOff = 0    # Время простоя ступени в секундах

    def incTime(self):
        '''
        Увеличивает счетчики времени работы или простоя ступени.
        Каждые 60 секунд увеличивает регистр на 1 минуту.
        '''
        if self.doPower.val():
            self.timeOn += 1
            if self.timeOn % 60 == 0:
                self.reg.inc()
        else:
            self.timeOff += 1

    def setPower(self, power, reason):
        '''
        Устанавливает состояние питания ступени и сбрасывает счетчики.
        Выводит сообщение о причине изменения состояния.
        '''
        self.timeOn = 0
        self.timeOff = 0
        self.doPower.val(power)
        print(f'Freon #{self.num} power {"on" if power else "off"} by {reason}')

    def on(self, reason):
        '''
        Включает ступень с указанной причиной.
        '''
        self.setPower(True, reason)

    def off(self, reason):
        '''
        Выключает ступень с указанной причиной.
        '''
        self.setPower(False, reason)

# Количество ступеней фреонового охладителя
FREON_COUNT = const(3)

# Конфигурация количества регистров, аналоговых/цифровых входов и выходов контроллера
count(Reg=6 + FREON_COUNT, Ai=1, Do=FREON_COUNT, Di=0, Ao=0)

# Конфигурация панели управления
webconf(Reg=True, Display=False, Pin=True, Console=True)

# Конфигурация пользовательских регистров
rPower       = Reg(0).conf(name='Питание', type='bool')                                                          # Основное питание установки
rSetTemp     = Reg(1).conf(name='Уставка', type='int', limits=[10, 45], default=25)                               # Заданная температура
rHysteresis  = Reg(2).conf(name='Гистерезис +/-', type='uint', limits=[0, 10], default=3, access='w')            # Гистерезис температуры
rRotationTime= Reg(3).conf(name='Ротация, час', type='uint', limits=[0, 24], step=1, default=30, access='w')      # Время ротации ступеней в часах
rDelay       = Reg(4).conf(name='Задержка, мин', type='uint', limits=[0, 60], step=1, default=1, access='w')      # Задержка между переключениями в минутах
rCounter     = Reg(5).conf(name='Счетчик, сек', type='uint', default=0, access='r')                              # Счетчик задержки в секундах

# Конфигурация аналогового входа с датчиком температуры
aiTemp       = Ai(0).conf(name='Температура в помещении', type='ntc', access='r')                                # Температура окружающей среды

# Инициализация массива объектов ступеней фреонового охладителя
freons = [FreonCooler(i + 1, Do(i), Reg(6 + i)) for i in range(FREON_COUNT)]

# Проверка и сброс счетчика при превышении задержки
if rCounter.val() > rDelay.val() * 60:
    rCounter.val(0)

def freonAlgo():
    '''
    Основной алгоритм управления фреоновым охладителем.
    Выполняется каждую секунду.
    '''
    # Обработка изменения состояния питания
    if rPower.changed():
        if not rPower.val():
            # Если питание отключено, выключаем все работающие ступени
            for freon in freons:
                if freon.doPower.val():
                    freon.off('powerOff')

    # Если питание отключено, прекращаем выполнение алгоритма
    if not rPower.val():
        return

    # Обработка задержки между переключениями ступеней
    if rCounter.val() > 0:
        rCounter.dec()
        return

    # Инициализация переменных для логики работы
    countOn = 0            # Количество включенных ступеней
    freonOnMax = None     # Ступень с максимальным временем работы
    freonOffMax = None    # Ступень с максимальным временем простоя

    # Обновление времени работы/простоя каждой ступени и определение max ступеней
    for freon in freons:
        freon.incTime()
        if freon.doPower.val():
            countOn += 1
            if (freonOnMax is None) or (freon.timeOn > freonOnMax.timeOn):
                freonOnMax = freon
        else:
            if (freonOffMax is None) or (freon.timeOff > freonOffMax.timeOff):
                freonOffMax = freon

    # Получение текущей температуры и настроек
    tempIn = aiTemp.val()
    tempOn = rSetTemp.val() + rHysteresis.val()
    tempOff = rSetTemp.val() - rHysteresis.val()
    rotationTimeSec = rRotationTime.val() * 60 * 60  # Конвертация часов в секунды

    # Логика включения ступеней при повышении температуры
    if tempIn > tempOn and countOn < FREON_COUNT:
        if freonOffMax is not None:
            freonOffMax.on('temp')
            rCounter.val(rDelay.val() * 60)  # Установка задержки

    # Логика выключения ступеней при понижении температуры
    elif tempIn < tempOff and countOn > 0:
        if freonOnMax is not None:
            freonOnMax.off('temp')
            rCounter.val(rDelay.val() * 60)  # Установка задержки

    # Логика ротации ступеней по времени
    elif rotationTimeSec > 0 and freonOnMax is not None and freonOnMax.timeOn > rotationTimeSec and freonOffMax is not None:
        freonOnMax.off('rotation')
        freonOffMax.on('rotation')
        rCounter.val(rDelay.val() * 60)  # Установка задержки

# Запуск алгоритма с периодичностью 1 секунда
run(freonAlgo, 1)