Форум самогонщиков Сайт Барахолка Магазин Помощь солдатам

Ненавязчивая автоматизация ректификационной установки

Форум самогонщиков Автоматика
1 ... 55 56 57 58 59 60 61 ... 132 58
Dmi_D Кандидат наук Минск 393 138
Отв.1140  10 Февр. 18, 23:16
Извини, но просто повторяюсь
https://ru.aliexpress.com/...2816412117.html
Это именно мини-UPS на одной плате.
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1141  11 Февр. 18, 00:06, через 50 мин
Извини, но просто повторяюсьDmi_D, 10 Февр. 18, 23:16
Пардон, не внимателен. Да, я видел.
Полезно почитать отзывы, прежде чем покупать.
к примеру нашел
"прежде всего это не UPS! продавцом, используя это слово в описании .. я тестировал его, и если Я отрезать власти в филиал выход всегда есть задержки и например оранжевый PI перезагрузки сам .. The consumption of Orange PI ~ 0.32A так очень малый ток, но даже с этой небольшой ток это устройство не может вести себя, как UPS!"
Т.е Orange PI на нем перегружается. Наша Малинка думаю тоже не вытерпит это...
Да и по отзывам, греется как печка.
На нетребовательную слаботочку может сгодится.
Dmi_D Кандидат наук Минск 393 138
Отв.1142  11 Февр. 18, 00:30, через 24 мин
Прости, не понял, о чем ты.
В смысле, это отзыв на твою или на мою ссылку?
BogAD Кандидат наук Красногорск - Белово 403 184
Отв.1143  11 Февр. 18, 01:31
Имел ввиду твой вариант
ru.aliexpress.com

Dmi_D Кандидат наук Минск 393 138
Отв.1144  11 Февр. 18, 01:38, через 8 мин
Я уже после поста перерыл отзывы....
Давай так - я получаю модуль, тестирую, отчитываюсь.
А то делим шкуру, а медведя, может, и не было.
Тайм-аут до получения посылки.
ZagAl Доцент Прибалтика 1.9K 916
Отв.1145  12 Февр. 18, 14:01
Всем, доброго дня.
В связи с тем, что у меня часто выбивает термодатчики (подключены к raspberry Pi Zero), решил поизучать этот вопрос.
Сделал программу на основе nna_02.py
Скрытый текст#coding:utf-8
import sys, os, time
import collections
"""Архив с модулями  sens, contr и kbh находятся в приложении к
  данному топику"""
import sens, contr, kbh

"""Сначала создаем объекты, соответствующие датчикам и контроллерам.
  Параллельно производится проверка их наличия и работоспособности.

  Начнем с датчиков температуры (DS18B20). Идентификаторы датчиков,
  установленных в системе известны. Определяем соответствующие
  переменные"""
hid = 0x8000001ee27b # ID датчика температуры куба
cid = 0x8000001ef6e6 # ID датчика температуры колонны
did = 0x000006273720 # ID датчика температуры дефлегматора
wid = 0x8000000419af # ID датчика температуры выходящей воды
"""Создаем вспомогательный список tids, для удобства коллективной
  работы со всеми датчиками"""
tids = (hid, cid, did, wid)
"""Статический метод Ts() класса DS18B20 возвращает словарь, содержащий
  пары {идентификатор датчика : его температура} для всех датчиков,
  подключенных к шине 1-Wire"""
Ts = sens.DS18B20.Ts()
"""Проверим, все ли датчики, с идентификаторами, перечисленными выше,
  есть в этом словаре (т.е. висят на шине и исправны)"""
flag = False
for id in tids: # Пробегаем по списку нужных нам датчиков
 if Ts.get(id) != None: # Соответствующий ключ (id) есть есть в словаре
   print "0x%012x :% 7.3f°C" % (id, Ts[id]) # Доложим об этом...
 else: # Увы...
   print "Датчик с ID = 0x%012x отсутствует или неисправен" % (id)
   flag = True # Выставляем флаг, что нужного датчика нет на шине
if flag:
 print "Один или более датчиков DS18B20 отсутствуют или неисправны. Завершение работы."
 sys.exit(1)
#-----------------------------------------------------------------------
"""Это начало общего отсчета времени (относительное время программы)
  и момент начала текущего режима работы"""
tst = rst = time.time()
#-----------------------------------------------------------------------
i=0
#-----------------------------------------------------------------------
"""Все. Все подготовительные операции закончены. Входим в главный
  цикл приложения"""
while True:
#-----------------------------------------------------------------------
 i+=1; ss = "% 5d" % (i)  # Счетчик циклов
#-----------------------------------------------------------------------
 """Сначала общая длительность процесса на данный момент и длительность
    текущего режима"""
 now = time.time(); dtm = (now - tst)/60.0
 ss += "% 7.2f" % (dtm)
#-----------------------------------------------------------------------
 """Добавим для выдачи текущие значения температур с датчиков"""
 Ts = sens.DS18B20.Ts() # Сначала их измерим
 for id in tids: # Теперь добавим в строки для выдачи
   if id == cid: # Подкрасим температуру в колонне для консоли
     ss += "\x1b[32m% 6.2f\x1b[0m" % (Ts[id])
   else: ss += "% 6.2f" % (Ts[id])
#-----------------------------------------------------------------------
 print ss # и выводим на экран
 time.sleep(5)
В результате, если в процессе работы программы отключить датчики, на экране будут отображаться нули. Если подключить датчики, то показания восстанавливаются. В первой строке, после восстановления показаний, может отображаться 85.0. Если не подключать датчики, то через 21 шаг происходит сбой программы. Первый вопрос: почему в течение 21 шага отображаются нули?
2018-02-12-113449_635x822_scrot.png
2018-02-12-113449_635x822_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Изменил программу, добавив команду на завершение работы программы в случае если датчик отвалился.
Скрытый текст#coding:utf-8
import sys, os, time
import collections
"""Архив с модулями  sens, contr и kbh находятся в приложении к
  данному топику"""
import sens, contr, kbh
#import contrSTPR, sensWEIGHT
#--------------------------------------------------------------------------------
"""Сначала создаем объекты, соответствующие датчикам и контроллерам.
  Параллельно производится проверка их наличия и работоспособности.
#--------------------------------------------------------------------------------
  Начнем с датчиков температуры (DS18B20). Идентификаторы датчиков,
  установленных в системе известны. Определяем соответствующие
  переменные"""
hid = 0x8000001ee27b # ID датчика температуры куба
cid = 0x8000001ef6e6 # ID датчика температуры колонны
did = 0x000006273720 # ID датчика температуры дефлегматора
wid = 0x8000000419af # ID датчика температуры выходящей воды
"""Создаем вспомогательный список tids, для удобства коллективной
  работы со всеми датчиками"""
tids = (hid, cid, did, wid)
"""Статический метод Ts() класса DS18B20 возвращает словарь, содержащий
  пары {идентификатор датчика : его температура} для всех датчиков,
  подключенных к шине 1-Wire"""
Ts = sens.DS18B20.Ts()
"""Проверим, все ли датчики, с идентификаторами, перечисленными выше,
  есть в этом словаре (т.е. висят на шине и исправны)"""
flag = False
for id in tids: # Пробегаем по списку нужных нам датчиков
 if Ts.get(id) != None: # Соответствующий ключ (id) есть есть в словаре
   print "0x%012x :% 7.3f°C" % (id, Ts[id]) # Доложим об этом...
 else: # Увы...
   print "Датчик с ID = 0x%012x отсутствует или неисправен" % (id)
   flag = True # Выставляем флаг, что нужного датчика нет на шине
if flag:
 print "Один или более датчиков DS18B20 отсутствуют или неисправны. Завершение работы."
 sys.exit(1)

#--------------------------------------------------------------------------------
"""Это начало общего отсчета времени (относительное время программы)
  и момент начала текущего режима работы"""
tst = rst = time.time()
#--------------------------------------------------------------------------------
i=0
#--------------------------------------------------------------------------------
"""Все. Все подготовительные операции закончены. Входим в главный
  цикл приложения"""
while True:
#--------------------------------------------------------------------------------
 i+=1; ss = "% 5d" % (i)  # Счетчик циклов
#--------------------------------------------------------------------------------
 """Сначала общая длительность процесса на данный момент и длительность
    текущего режима"""
 now = time.time(); dtm = (now - tst)/60.0
 ss += "% 7.2f" % (dtm)
#--------------------------------------------------------------------------------
 """Добавим для выдачи текущие значения температур с датчиков"""
 Ts = sens.DS18B20.Ts() # Сначала их измерим
 flag = False
 for id in tids: # Теперь добавим в строки для выдачи
   if id in Ts:  # Если датчик с таким ID есть в словаре, то выведем его температуру
     if id == hid: # Датчик в кубе Tcub
       Tcub = Ts[id]
       ss += "% 7.2f" % (Tcub)
     if id == cid: # Подкрасим температуру в колонне для консоли и определим переменную Tcol
       Tcol = Ts[id]
       ss += "\x1b[32m %7.2f\x1b[0m" % (Tcol)
     if id == did: # Подкрасим температуру в дефлегматоре для консоли и определим переменную Tdef
       Tdef = Ts[id]
       ss += "\x1b[33m %7.2f\x1b[0m" % (Tdef)
     if id == wid: # Датчик холодильника Thol
       Thol = Ts[id]
       ss += "% 7.2f" % (Thol)
   else:
     ss += "\x1b[31m %6.2f\x1b[0m" % (0.) # А если такого датчика нет - ставим нули.
     flag = True
 if flag:
   print "Завершение работы"
   sys.exit(1)  
#--------------------------------------------------------------------------------
 print ss # и выводим на экран
 time.sleep(5)
Результат такой же как и прежде, за исключением того, что программа завершается по команде, но через те же 21 шаг, отображая при этом нули.
2018-02-12-114043_635x822_scrot.png
2018-02-12-114043_635x822_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

В следующей модификации программы, вместо команды завершения программы, дал команду на отображение нулей красным цветом.
Скрытый текст#coding:utf-8
import sys, os, time
import collections
"""Архив с модулями  sens, contr и kbh находятся в приложении к
  данному топику"""
import sens, contr, kbh
import contrSTPR, sensWEIGHT
#--------------------------------------------------------------------------------
"""Сначала создаем объекты, соответствующие датчикам и контроллерам.
  Параллельно производится проверка их наличия и работоспособности.
#--------------------------------------------------------------------------------
  Начнем с датчиков температуры (DS18B20). Идентификаторы датчиков,
  установленных в системе известны. Определяем соответствующие
  переменные"""
hid = 0x8000001ee27b # ID датчика температуры куба
cid = 0x8000001ef6e6 # ID датчика температуры колонны
did = 0x000006273720 # ID датчика температуры дефлегматора
wid = 0x8000000419af # ID датчика температуры выходящей воды
"""Создаем вспомогательный список tids, для удобства коллективной
  работы со всеми датчиками"""
tids = (hid, cid, did, wid)
"""Статический метод Ts() класса DS18B20 возвращает словарь, содержащий
  пары {идентификатор датчика : его температура} для всех датчиков,
  подключенных к шине 1-Wire"""
Ts = sens.DS18B20.Ts()
"""Проверим, все ли датчики, с идентификаторами, перечисленными выше,
  есть в этом словаре (т.е. висят на шине и исправны)"""
flag = False
for id in tids: # Пробегаем по списку нужных нам датчиков
 if Ts.get(id) != None: # Соответствующий ключ (id) есть есть в словаре
   print "0x%012x :% 7.3f°C" % (id, Ts[id]) # Доложим об этом...
 else: # Увы...
   print "Датчик с ID = 0x%012x отсутствует или неисправен" % (id)
   flag = True # Выставляем флаг, что нужного датчика нет на шине
if flag:
 print "Один или более датчиков DS18B20 отсутствуют или неисправны. Завершение работы."
 sys.exit(1)

#--------------------------------------------------------------------------------
"""Параметр timeout задает время ожидания нажатия клавиши (он может быть
  равен 0). В данном случае мы используем этот параметр для регулирования
  длительности одного такта главного цикла приложения. При timeout = 3000
  длительность такта составляет около 4 сек"""
#timeout = 3910 # В мс. Должно быть 5 сек.
#tt = kbh.TT(timeout)


"""Это начало общего отсчета времени (относительное время программы)
  и момент начала текущего режима работы"""
tst = rst = New_time = time.time()
#--------------------------------------------------------------------------------
i=0
#--------------------------------------------------------------------------------
"""Все. Все подготовительные операции закончены. Входим в главный
  цикл приложения"""
while True:
#--------------------------------------------------------------------------------
 i+=1; ss = "% 5d" % (i)  # Счетчик циклов
#--------------------------------------------------------------------------------
 """Сначала общая длительность процесса на данный момент и длительность
    текущего режима"""
 now = time.time(); dtm = (now - tst)/60.0
 ss += "% 7.2f" % (dtm)
#--------------------------------------------------------------------------------
 """Добавим для выдачи текущие значения температур с датчиков"""
 Ts = sens.DS18B20.Ts() # Сначала их измерим
 for id in tids: # Теперь добавим в строки для выдачи
   if id in Ts:  # Если датчик с таким ID есть в словаре, то выведем его температуру
     if id == hid: # Датчик в кубе Tcub
       Tcub = Ts[id]
       ss += "% 7.2f" % (Tcub)
     if id == cid: # Подкрасим температуру в колонне для консоли и определим переменную Tcol
       Tcol = Ts[id]
       ss += "\x1b[32m %7.2f\x1b[0m" % (Tcol)
     if id == did: # Подкрасим температуру в дефлегматоре для консоли и определим переменную Tdef
       Tdef = Ts[id]
       ss += "\x1b[33m %7.2f\x1b[0m" % (Tdef)
     if id == wid: # Датчик холодильника Thol
       Thol = Ts[id]
       ss += "% 7.2f" % (Thol)
   else: ss += "\x1b[31m %6.2f\x1b[0m" % (0.) # А если такого датчика нет - ставим нули.
#--------------------------------------------------------------------------------
 time.sleep(5)
 print ss # и выводим на экран
В результате после 21-го шага отображения нулей, начинают бесконечно отображаться нули красного цвета. Сама программа не завершается. То есть во всех этих трех вариантах, команда else:, непонятно почему выполняется только через 21 шаг после возникновения проблемы.
2018-02-12-115044_635x822_scrot.png
2018-02-12-115044_635x822_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Новая модификация программы:
Скрытый текст#coding:utf-8
import sys, os, time
import collections
"""Архив с модулями  sens, contr и kbh находятся в приложении к
  данному топику"""
import sens, contr, kbh
import contrSTPR, sensWEIGHT
import RPi.GPIO as GPIO
ReadSensors = False
#-----------------------------------------------------------------------
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD) # Определяем пины по номерам
GPIO.setup(12, GPIO.OUT) # Пин 12 - вывод
GPIO.output(12,1)        # Подаем высокое на пин 12  
time.sleep(2)
"""Сначала создаем объекты, соответствующие датчикам и контроллерам.
  Параллельно производится проверка их наличия и работоспособности.
#-----------------------------------------------------------------------
  Начнем с датчиков температуры (DS18B20). Идентификаторы датчиков,
  установленных в системе известны. Определяем соответствующие
  переменные"""
hid = 0x8000001ee27b # ID датчика температуры куба
cid = 0x8000001ef6e6 # ID датчика температуры колонны
did = 0x000006273720 # ID датчика температуры дефлегматора
wid = 0x8000000419af # ID датчика температуры выходящей воды
"""Создаем вспомогательный список tids, для удобства коллективной
  работы со всеми датчиками"""
tids = (hid, cid, did, wid)
"""Статический метод Ts() класса DS18B20 возвращает словарь, содержащий
  пары {идентификатор датчика : его температура} для всех датчиков,
  подключенных к шине 1-Wire"""
Ts = sens.DS18B20.Ts()
"""Проверим, все ли датчики, с идентификаторами, перечисленными выше,
  есть в этом словаре (т.е. висят на шине и исправны)"""
flag = False
for id in tids: # Пробегаем по списку нужных нам датчиков
 if Ts.get(id) != None: # Соответствующий ключ (id) есть есть в словаре
   print "0x%012x :% 7.3f°C" % (id, Ts[id]) # Доложим об этом...
 else: # Увы...
   print "Датчик с ID = 0x%012x отсутствует или неисправен" % (id)
   flag = True # Выставляем флаг, что нужного датчика нет на шине
if flag:
 print "Один или более датчиков DS18B20 отсутствуют или неисправны. Завершение работы."
 sys.exit(1)

#-----------------------------------------------------------------------
"""Это начало общего отсчета времени (относительное время программы)
  и момент начала текущего режима работы"""
tst = rst = New_time = time.time()
#-----------------------------------------------------------------------
i=0 # Общий счетчик
error_counter = 0 # Счетчик ошибок
#-----------------------------------------------------------------------
"""Все. Все подготовительные операции закончены. Входим в главный
  цикл приложения"""
while True:
#-----------------------------------------------------------------------
 i+=1; ss = "% 5d" % (i)
 """Теперь довольно громоздкий блок в котором мы измеряем все доступные
    текущие параметры процесса и формируем две строки. Одна (ss) краткая
    и раскрашенная для вывода информации на консоль. Вторая (s)
    "ненакрашенная" и (обычно) более подробная - для записи в журнал"""
#-----------------------------------------------------------------------
 """Сначала общая длительность процесса на данный момент и длительность
    текущего режима"""
 now = time.time(); dtm = (now - tst)/60.0
 ss += "% 7.2f" % (dtm)
#-----------------------------------------------------------------------
 while ReadSensors == False:
   print "Считываю датчики"
   Ts = sens.DS18B20.Ts() # Считаем датчики
   if Ts.get(id) != None and Ts[id] != 0: # Соответствующий ключ (id) есть есть в словаре
     ReadSensors = True
     if Ts[id] == 85.:
       ReadSensors = False
       time.sleep(2)
       print "Температура = %4.1f Возвращаюсь к считыванию датчиков." % (Ts[id])
       continue
     print "Датчики считаны"
   else: # Увы...
     print "Датчики отсутствуют или неисправны"
     ReadSensors = False #
     GPIO.output(12,0) # Отключаем 3.3V от DS18B20
     print "Отключаю питание"
     time.sleep(0.2)
     GPIO.output(12,1) # Включаем 3.3V на DS18B20
     print "Включаю питание"
     error_counter += 1
     time.sleep(2)
     
 for id in tids: # Теперь добавим в строки для выдачи
   if id in Ts:  # Если датчик с таким ID есть в словаре, то выведем его температуру
     if id == hid: # Датчик в кубе Tcub
       Tcub = Ts[id]
       ss += "% 7.2f" % (Tcub)
     if id == cid: # Подкрасим температуру в колонне для консоли и определим переменную Tcol
       Tcol = Ts[id]
       ss += "\x1b[32m %7.2f\x1b[0m" % (Tcol)
     if id == did: # Подкрасим температуру в дефлегматоре для консоли и определим переменную Tdef
       Tdef = Ts[id]
       ss += "\x1b[33m %7.2f\x1b[0m" % (Tdef)
     if id == wid: # Датчик холодильника Thol
       Thol = Ts[id]
       ss += "% 7.2f" % (Thol)
#-----------------------------------------------------------------------
 ss += "% 5d" % (error_counter)
 print ss # и выводим на экран
 time.sleep(5)
 ReadSensors = False
Так как после кратковременного отключения датчиков и последующего включения, показания восстанавливаются, пришла идея сделать так, чтобы при сбое датчика, автоматически отключалось и включалось питание. Для этого подключил питание датчиков к GPIO18 (pin 12).
2018-02-12-120200_635x822_scrot.png
2018-02-12-120200_635x822_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Казалось бы, проблема разрешилась. Но при использовании этого блока в основной программе происходит следующее - после восстановления питания, не понятно от куда появляются нули. Четыре группы нулей - по количеству датчиков. И если датчики не подключать в течение более длительного времени, то и количество групп нулей возрастает кратно количеству сообщений о неисправности датчиков.
2018-02-12-120937_995x966_scrot.2.png
2018-02-12-120937_995x966_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Скрытый текст#coding:utf-8
import sys, os, time
import collections
"""Архив с модулями  sens, contr и kbh находятся в приложении к
  данному топику"""
import sens, contr, kbh
import contrSTPR, sensWEIGHT
import RPi.GPIO as GPIO
ReadSensors = False
Tcol_list=[]
Tdef_list=[]
dWeight = 0
dWeight1 = 0
Column_stabilized = False
Tcol_max = False
Max_ekstremum = False
Temperature_grows = False
wght_new = 0
wght_correct = 0
Old_Weight = 0
Start_time = 0
Finish_time = 0
Sel_Speed = 0
dTime = 0
#--------------------------------------------------------------------------------
"""Сначала создаем объекты, соответствующие датчикам и контроллерам.
  Параллельно производится проверка их наличия и работоспособности.
#--------------------------------------------------------------------------------
  Начнем с датчиков температуры (DS18B20).
  Подключаем питание датчиков на пин 12 (GPIO 18), определяем его как
  пин вывода и подаем на него 1 (3.3V). """
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD) # Определяем пины по номерам
GPIO.setup(12, GPIO.OUT) # Пин 12 - вывод
GPIO.output(12,1)        # Подаем высокое на пин 12  
time.sleep(2)
"""Идентификаторы датчиков,
  установленных в системе известны. Определяем соответствующие
  переменные"""  
hid = 0x8000001ee27b # ID датчика температуры куба
cid = 0x8000001ef6e6 # ID датчика температуры колонны
did = 0x000006273720 # ID датчика температуры дефлегматора
wid = 0x8000000419af # ID датчика температуры выходящей воды
"""Создаем вспомогательный список tids, для удобства коллективной
  работы со всеми датчиками"""
tids = (hid, cid, did, wid)
"""Статический метод Ts() класса DS18B20 возвращает словарь, содержащий
  пары {идентификатор датчика : его температура} для всех датчиков,
  подключенных к шине 1-Wire"""
Ts = sens.DS18B20.Ts()
"""Проверим, все ли датчики, с идентификаторами, перечисленными выше,
  есть в этом словаре (т.е. висят на шине и исправны)"""
flag = False
for id in tids: # Пробегаем по списку нужных нам датчиков
 if Ts.get(id) != None: # Соответствующий ключ (id) есть есть в словаре
   print "0x%012x :% 7.3f°C" % (id, Ts[id]) # Доложим об этом...
 else: # Увы...
   print "Датчик с ID = 0x%012x отсутствует или неисправен" % (id)
   flag = True # Выставляем флаг, что нужного датчика нет на шине
if flag:
 print "Один или более датчиков DS18B20 отсутствуют или неисправны. Завершение работы."
 sys.exit(1)
#--------------------------------------------------------------------------------
"""С датчиками температуры разобрались. Теперь займемся датчиком
  RMS (действующее напряжение сети)"""
vs = sens.RMS() # Создаем объект - датчик RMS
if vs != None: # Датчик в наличии и функционирует
 V = vs.V
 if V > 100: print "Действующее напряжение сети %d В" % (V)
 else:
   print "Слишком низкое напряжение сети. Завершение работы."
   sys.exit(2)
else: pass # Ну на нет и суда нет. Можно работать и без датчика RMS
#--------------------------------------------------------------------------------
"""Датчик атмосферного давления - полезная вещь. Проверим его наличие
  и работоспособность. Если его нет - не беда. Будем работать без него"""
ps = sens.BMP180() # Создаем объект - датчик атмосферного давления
if ps != None: # Датчик в наличии и функционирует
 print "Атмосферное давление: \t%5.1f мм.рт.ст." % (ps.P)
 print "Температура окружающей среды:\t%5.2f°C" % (ps.T)
#--------------------------------------------------------------------------------
"""Датчик веса."""
weight = sensWEIGHT.BALANCE()
if weight != None: #Датчик веса в наличии и функционирует
 print "Вес: %5.1f грамм." % (weight.B)
else: None
#--------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
"""Создаем объекты-контроллеры исполнительных устройств"""
#--------------------------------------------------------------------------------
teh = contr.TEH(vs) # Создадим объект "ТЭН"
if teh == None:
 print "Контроллер ТЭНа отсутствует или неисправен. Завершение работы."
 sys.exit(3)
#--------------------------------------------------------------------------------
#sd = contr.SD() # Создадим объект "устройство отбора"
"""В принципе можно работать и без клапана отбора. Например, с ручной
  "пережимкой". Если ситуация именно такова, то закомментируйте следующие
  три строчки"""
#if sd == None:
#  print "Контроллер клапана отбора отсутствует или неисправен. Завершение работы."
#  sys.exit(3)
#--------------------------------------------------------------------------------
Deflegmator=contrSTPR.STPR(addrSTPR=0x07)
if Deflegmator == None:
 print "Контроллер Дефлегматора отсутствует или неисправен. Завершение работы."
 sys.exit(4)
Holodilnik=contrSTPR.STPR(addrSTPR=0x08)
if Holodilnik == None:
 print "Контроллер Холодильника отсутствует или неисправен. Завершение работы."
 sys.exit(5)
#--------------------------------------------------------------------------------
#--------------------------------------------------------------------------------
"""Все. С датчиками и исполнительными устройствами мы разобрались.
  Теперь переведем консоль в неблокирующий режим работы. Это нужно
  для того, чтобы можно было бы в главном цикле приложения обрабатывать
  нажатие клавиш клавиатуры. Необходимый для этого сервис организован
  в виде класса TT, который находится в модуле kbh. При создании объекта
  (экземпляра этого класса) как раз и происходит переход консоли
  в неблокирующий режим. При уничтожении объекта (в деструкторе)
  консоль возвращается к обычному режиму работы.

  Параметр timeout задает время ожидания нажатия клавиши (он может быть
  равен 0). В данном случае мы используем этот параметр для регулирования
  длительности одного такта главного цикла приложения. При timeout = 3000
  длительность такта составляет около 4 сек"""
timeout = 3910 # В мс. Должно быть 5 сек.
tt = kbh.TT(timeout)

"""Теперь сформируем карту режимов, доступных в данном приложении. Режимы
  пронумерованы от 0 до 6. Карта режимов представляет собой список
  именованных кортежей (т.е. к элементам кортежа можно обращаться
  по имени). Это очень удобно. Имена элементов кортежа:
  W     - мощность нагрева ТЭНа, Вт (вещественное число)
  stab  - стабилизация мощности нагрева ТЭНа (True/False)
  Q     - скорость отбора, мл/час (вещественное число)
  ststp - режим старт-стопа (True/Flase)"""
#-------------------------------------------------------------------------------
mrec = collections.namedtuple('mrec', 'W stab Q ststp')
modes = [] # Собственно список режимов
modes.append(mrec(0, False, 0, False))        # 0 - Только мониторинг
modes.append(mrec(2000, False, 0, False))     # 1 - Разгон
modes.append(mrec(650, True, 0, False))       # 2 - Стабилизация с выходом на отбор голов
modes.append(mrec(600, True, 40, False))      # 3 - Отбора голов
modes.append(mrec(600, True, 400, True))      # 4 - Отбора тела
modes.append(mrec(600, True, 400, False))     # 5 - Отбор хвостов
modes.append(mrec(2000, False, 1000, False))  # 6 - Пропарка колонны
#--------------------------------------------------------------------------------
mode = old_mode = 0 # Начинаем работать всегда с нулевого режима

"""Это начало общего отсчета времени (относительное время программы)
  и момент начала текущего режима работы"""
tst = rst = New_time = time.time()

"""Теперь откроем файл журнала. Здесь возможны две ситуации. В первом
  варианте мы продолжаем прерванный ранее процесс ректификации. В этом
  случае нам удобно продолжить вести уже существующий файл журнала и
  отсчет времени. Т.е. если файл журнала есть и он не слишком мал,
  то мы так и поступим. Если же файла нет или он мал - то открываем
  новый файл и вдем отсчет локального времени процесса с нуля."""
if os.path.exists("log") and os.path.getsize("log") > 127:
 log = open("log", "r") # Нужно прочитать последнюю строку
 log.seek(-127, 2) # Встанeм немного недоходя до конца файла
 for line in open("log", "r"): # и считаем последнюю строку
   last_line = line
 prevStopTime = float(last_line.split()[1])
 tst -= prevStopTime*60.0 # Локальное время будет продолжаться с конца
                          # предыдущей сессии
 log.close()
 log = open("log", "a") # А теперь откроем его уже для добавления
else: # В противном случае создаем новый файл журнала а нулевое
 log = open("log", "w") # локальное время уже установлено выше
#--------------------------------------------------------------------------------
"""Все. Все подготовительные операции закончены. Входим в главный
  цикл приложения"""
while True:
#--------------------------------------------------------------------------------
 """Сначала посмотрим на состояние клавиатуры"""
 if tt.kbhit(): # Какая-то клавиша уже была нажата
   ch = tt.getch() # Смотрим что было нажато....
   if ch == 'q':
     #GPIO.output(12,0) # Отключаем 3.3V
     GPIO.cleanup()
     break # Выходим из цикла - конец работы
   elif ord(ch) >= 48 and ord(ch) <= 57: # Ввели номер режима
     old_mode = mode; mode = int(ch)
#--------------------------------------------------------------------------------
 """Теперь довольно громоздкий блок в котором мы измеряем все доступные
    текущие параметры процесса и формируем две строки. Одна (ss) краткая
    и раскрашенная для вывода информации на консоль. Вторая (s)
    "ненакрашенная" и (обычно) более подробная - для записи в журнал"""
#--------------------------------------------------------------------------------
 """Сначала общая длительность процесса на данный момент и длительность
    текущего режима"""
 now = time.time(); dtm = (now - tst)/60.0; dtrm = (now - rst)/60.0
 ss = "% 7.2f % 7.2f\x1b[33m %d\x1b[0m" % (dtm, dtrm, mode)
 """Для журнала добавляем еще и глобальное время"""
 s = time.strftime("%y.%m.%d.%H.%M.%S")
 s += "% 7.2f % 7.2f %d" % (dtm, dtrm, mode)
 """Проверим и выведим информацию о продолжительности цикла.."""
 Old_time = New_time
 New_time = time.time()
 Duration_of_cycle = New_time - Old_time
 """Выводим информацию о продолжительности цикла."""
 ss += "% 2d" % (Duration_of_cycle)
#-----------------------------------------------------------------------
 """Добавим для выдачи текущие значения температур с датчиков"""
 while ReadSensors == False:
   print "Считываю датчики"
   Ts = sens.DS18B20.Ts() # Считаем датчики
   if Ts.get(id) != None and Ts[id] != 0: # Соответствующий ключ (id) есть есть в словаре
     ReadSensors = True
     if Ts[id] == 85.:
       ReadSensors = False
       time.sleep(2)
       print "Температура = %4.1f Возвращаюсь к считыванию датчиков." % (Ts[id])
       continue
     if Ts[id] == 0.:
       ReadSensors = False
       time.sleep(2)
       print "Температура = %4.1f Возвращаюсь к считыванию датчиков." % (Ts[id])
       continue  
     print "Датчики считаны"
   else: # Увы...
     print "Датчики отсутствуют или неисправны"
     ReadSensors = False #
     GPIO.output(12,0) # Отключаем 3.3V от DS18B20
     print "Отключаю питание"
     time.sleep(0.2)
     GPIO.output(12,1) # Включаем 3.3V на DS18B20
     print "Включаю питание"
     #error_counter += 1
     time.sleep(2)
     
   for id in tids: # Теперь добавим в строки для выдачи
     if id in Ts:  # Если датчик с таким ID есть в словаре, то выведем его температуру
       if id == hid: # Датчик в кубе Tcub
         Tcub = Ts[id]
         ss += "% 7.2f" % (Tcub); s +=  "% 7.3f" % (Tcub)
       if id == cid: # Подкрасим температуру в колонне для консоли и определим переменную Tcol
         Tcol = Ts[id]
         ss += "\x1b[32m %7.2f\x1b[0m" % (Tcol); s +=  "% 7.3f" % (Tcol)
       if id == did: # Подкрасим температуру в дефлегматоре для консоли и определим переменную Tdef
         Tdef = Ts[id]
         ss += "\x1b[33m %7.2f\x1b[0m" % (Tdef); s +=  "% 7.3f" % (Tdef)
       if id == wid: # Датчик холодильника Thol
         Thol = Ts[id]
         ss += "% 7.2f" % (Thol); s +=  "% 7.3f" % (Thol)
#-----------------------------------------------------------------------
 """Измеряем и выводим текущую мощность нагрева"""
 cW = teh.W
 ss += "\x1b[31m %4d\x1b[0m" % (cW); s +=  " %5d" % (cW)
#-----------------------------------------------------------------------
 """Если есть датчик RMS, то в журнал выведем напряжение в сети"""
 if vs != None:
   V = vs.V; ss +=  " %3d" % (V); s +=  " %4d" % (V)
#-----------------------------------------------------------------------
 """Если есть датчик атмосферного давления - выводим давление"""
 if ps != None:
   P = ps.P; ss += "% 6.1f" % (P); s += "% 5.1f" % (P)
#-----------------------------------------------------------------------
 """Заполняем список и выводим информацию об изменении температуры в колонне"""
 if len(Tcol_list) <= 4:
   Tcol_list.append(Tcol)
#    ss += "\x1b[32m% 6.2f\x1b[0m" % (0.)
 else:
   del Tcol_list[0]
   Tcol_list.append(Tcol)
   dTcol = Tcol_list[4] - Tcol_list[0]
#    ss += "\x1b[32m% 6.2f\x1b[0m" % (dTcol)
#-----------------------------------------------------------------------
 """Заполняем список и выводим информацию об изменении температуры в дефлегматоре"""
 if len(Tdef_list) <= 4:
   Tdef_list.append(Tdef)
#    ss += "\x1b[33m% 6.2f\x1b[0m" % (0.)
 else:
   del Tdef_list[0]
   Tdef_list.append(Tdef)
   dTdef = Tdef_list[4] - Tdef_list[3]
#    ss += "\x1b[33m% 6.2f\x1b[0m" % (dTdef)
#-----------------------------------------------------------------------
 """Выводим информацию о положении кранов."""
 ss += "% 4d" % (Deflegmator.N); s += "% 4d" % (Deflegmator.N)
 ss += "% 4d" % (Holodilnik.N); s += "% 4d" % (Holodilnik.N)
#-----------------------------------------------------------------------
 """Выводим информацию с датчика веса."""
 weight = sensWEIGHT.BALANCE()
 if weight != None:
   weight.B = 0 # Посылаем 0 чтобы считывать вес.  
   Nou_weight = weight.B # Получаем значение реального веса.
   if Nou_weight == 0:
     wght_new = 0.
     #Nou_weight = 0.
     wght_correct = 0.
   else:
     wght_old = wght_new
     wght_new = weight.B
     if wght_new < wght_old:
       wght_correct += 200.
   Nou_weight = wght_correct + wght_new
   weight.B=1
   Counter=weight.B/10. # Считывает значение счетчика капель
 else: None
 ss += "% 5d" % (Nou_weight); s += "% 5d" % (Nou_weight) # С Ардуинки принимаем целое число.
 ss +=  "\x1b[32m %5.1f\x1b[0m" % (Counter); s += "% 5.1f" % (Counter)
#-----------------------------------------------------------------------
 """Выводим информацию о временном интервале, приросте веса и возможной скорости отбора."""
 dWeight = Nou_weight - Old_Weight
 if Old_Weight == 0: dWeight = 0
 if dWeight > 0:
   dWeight1 = dWeight
   Finish_time = New_time
   dTime = Finish_time - Start_time
   if dTime > 1000: dTime = 0
   Start_time = Finish_time
   if dTime > 0:
     Sel_Speed = dWeight/dTime*3600
 ss += "\x1b[33m% 5.1f\x1b[0m" % (dTime)
 ss += "% 5.1f" % (dWeight1)
 ss += "% 4d" % (Sel_Speed)
 Old_Weight = Nou_weight
#--------------------------------------------------------------------------------
 """Далее собственно и следует вся ненавязчивая автоматизация :)))

    В данной задаче автоматическое переключение режимов нужно только
    для стадии разгона. Т.е. в режиме разгона (режим 1) после закипания,
    когда температура в 1/3 колонны превысит, скажем, 60°C, нужно
    перейти в режим 2 (сбросить мощность на "штатный" уровень).
    Ну так так и объясняем малинке."""
#--------------------------------------------------------------------------------
 if mode == 1: # Текущий режим - разгон
   if Tcol != 0: # Если датчики температуры исправны, то...
     if Tcol >= 60: # Куб закипел - пора сбрасывать мощность
       old__mode = mode; Deflegmator.N=130; Holodilnik.N=10; mode = 2
   else: # Если датчик заглючил, то Tcol = 0. Завершаем работу.
     print "Термодатчик неисправен. Завершение работы."
     sys.exit(6)     
#--------------------------------------------------------------------------------
 if mode == 2:   # Текущий режим - стабилизация с выходом на отбор голов
   if Tdef != 0:
     if Tdef_list[4] + 7 < Tcol_list[4]:  # Регулируем кран дефлегматора только до заданной температуры.
       if Column_stabilized == False:  # Если колонна не стабилизирована
         if Tcol_max == False and Tcol_list[2] > Tcol_list[4]: Tcol_max = True; print 'Максимум температуры колонны пройден.'
         if Tcol_max == True and Tcol_list[2]-Tcol_list[4] < 0.1: Column_stabilized = True; print 'Начало стабилизации колонны.'
       if Column_stabilized == True: # Началась стабилизация
         if Temperature_grows == False and Tdef_list[4]>Tdef_list[2]>Tdef_list[0]: Temperature_grows = True
         if Temperature_grows == True and Tdef_list[4] <= Tdef_list[2]:
           Max_ekstremum = True; Temperature_grows = False;
           if Tdef_list[4] < 50: oldDef = Deflegmator.N; Deflegmator.N = Deflegmator.N - 10
           else: oldDef= Deflegmator.N; Deflegmator.N = Deflegmator.N - 7
         if Deflegmator.N < 40: Deflegmator.N = oldDef
   else: None # Если датчик температуры заглючил, то ничего не делаем.
#--------------------------------------------------------------------------------
 """  if mode == 3: # Текущий режим - отбор голов.
        if Tdef != 0:
          # Написать инструкции анализа веса.
        else: None # Если датчик температуры заглючил, то ничего не делаем.
 """
#--------------------------------------------------------------------------------
 """Теперь обработаем ситуацию, когда произошла смена режима работы
    установки (автоматически, или по нажатию клавиши). Для обработки
    используем карту режимов"""
 if old_mode != mode:
   """Для режимов без стабилизации мощности (разгон, пропарка колонны и т.п.)
      мощность устанавливается только один раз при смене режима"""
   if not modes[mode].stab and mode != 0: teh.W = modes[mode].W              
#   sd.Q = modes[mode].Q # А вот для скорости отбора мы так делаем всегда
   old_mode = mode
   rst = now # Фиксируем момент начала нового режима
 """Для режимов со стабилизацией мощности (это написано в карте режимов),
    мощность обновляем на каждом такте главного цикла приложения
    (естественно, с учетом напряжения сети, если подключен датчик RMS)"""
 if modes[mode].stab:
   teh.W = modes[mode].W
#  """Включаем счетчик циклов. И если step_number>steps_in_circle
#     сбрасываем счетчик"""
#  step_number=step_number+1
#  if step_number>steps_in_circle:
#    step_number=1

 log.write(s + "\n"); log.flush() # Пишем данные в журнал
 print ss # и выводим на экран
 #-----------------------------------------------------------------------
 ReadSensors = False
Прошу помочь разобраться в этом вопросе.
OldBean Доцент Красноярск 1K 1.4K
Отв.1146  13 Февр. 18, 06:29
2ZagAl Александр, положите пожалуйста текст модуля sens.py, который Вы используете в своих тестах. Их было несколько версий (в том числе с различными вариантами работы с потоками при запуске Ds-ок). Ну чтобы у нас была однозначность.
ZagAl Доцент Прибалтика 1.9K 916
Отв.1147  13 Февр. 18, 11:15
OldBean, да, конечно нужно было сразу об этом подумать. Вот sens.py которым я пользуюсь.
Скрытый текст#coding:utf-8
"""Модуль sens содержит классы-обертки для датчиков, подключенных
к шинам 1-Wire и I2C микрокомпьютера Raspberry Pi
История изменений - в конце файла
OldBean, 17.01.26"""
import os, time, thread
import smbus
import Adafruit_BMP.BMP085 as bmp

#-------------------------------------------------------------------------------
class DS18B20(object): # Класс датчика температуры DS18B20
  """    Класс-обертка для датчиков DS18B20, подключенных к шине 1-Wire.
    Температура каждого объекта класса DS18B20 представляется свойством T.
    Цикл преобразования датчика запускается каждый раз, когда это
    свойство используется в правой части выражения.
    Класс DS18B20 также представляет средства для коллективной работы с
    датчиками: список всех датчиков, подключенных к шине 1-Wire (стаический
    метод IDs() и словарь, содержащий ключи - идентификаторы датчиков и
    значения - температуры соответствующих датчиков (статический метод Ts())"""
  path = "/sys/bus/w1/devices" # Директория с файлами датчиков
  tsd = {} # Словарь для коллективной работы с датчиками {id датчика : температура}

  def __new__(cls, id):
    """ Перед созданием объекта В методе __new__ производится проверка
        наличия датчика DS18B20 с заданным id"""
    dn = cls.path + ("/28-%012x" % (id))
    if os.path.isdir(dn):
      return super(DS18B20, cls).__new__(cls)
    else:
      print "Датчик c id = 0x%012x  отсутствует или неисправен" % (id)
      return None

  def __init__(self, id):
    """id - идентификатор датчика (число)"""
    self._id = id
    self._fn = DS18B20.path + ("/28-%012x/w1_slave" % (id))

  @staticmethod
  def temperature(fn, id = -1, lock = None):
    """      Запускается цикл преобразования одного датчика DS18B20.
      Если идентификатор датчика не установлен (по умолчанию),
      то просто возвращается значение температуры.
      Если же идентификатор датчика (параметр id) задан, то значение
      температуры записывается в словарь tsd. Ключом является id датчика.
      При таком режиме работы предполагается параллельная выполнение циклов
      преобразований датчиков. Поэтому по окончанию преобразования
      также освобождается и блокировка (параметр lock)."""
    lines = ["NoNoNo", ""]
    while not lines[0].strip().endswith("YES"): # Пока данные не будут готовы
      f = open(fn, "r")
      lines = f.readlines()
      f.close()
    pos = lines[1].find('t=') # Температура - после "t="
    temp = -273.15 # :)
    if pos != -1:
      temp = float(lines[1][pos + 2:])/1000 # Температура в Цельсиях
    if id < 0: return temp
    DS18B20.tsd[id] = temp
    lock.release()

  @property
  def T(self):
    """      Свойство - температура датчика. Цикл преобразования
      (около 750 мс) запускается при каждом использовании этого
      свойства в правой части выражения."""
    return DS18B20.temperature(self._fn)

  @staticmethod
  def IDs():
    """    Возвращает список идентификаторов всех датчиков DS18B20,
      подключенных к шине 1-Wire."""
    fnl = os.listdir(DS18B20.path)
    idl = []
    for fn in fnl:
      if fn.startswith("28-"): # Директория соответствует датчику DS18B20
        idl.append(int(fn[-12:], 16))
    return idl

  @staticmethod
  def Ts():
    """    Возвращает словарь, содержащий идентификаторы всех датчиков
    DS18B20, подключенных к шине 1-Wire (в качестве ключей словаря),
    и температуры датчиков (соответствующие значения словаря). Обработка
    каждого датчика производится параллельно в отдельном потоке, поэтому
    суммарное время преобразования всех датчиков существенно меньше, чем
    при последовательном опросе. Например для 4-х датчиков - 0.991 сек
    вместо 3.349 сек."""
    DS18B20.tsd.clear()
    ids = []; fns = []; locks = []
    dnl = os.listdir(DS18B20.path)
    for dn in dnl:
      if dn.startswith("28-"): # Директория соответствует датчику DS18B20
        ids.append(int(dn[-12:], 16)) # Выделяем ID датчика и - в список
        # Формируем полное имя файла с данными от датчика
        fns.append(DS18B20.path + "/" + dn + "/w1_slave")
        # Захватываем блокировки и заносим их в список блокировок
        lock = thread.allocate_lock()
        lock.acquire()
        locks.append(lock)
    nts = len(ids) # Количество датчиков DS18B20, подключенных к шине
    # Запускаем параллельные потоки циклов преобразований датчиков
    for i in range(nts):
      thread.start_new_thread(DS18B20.temperature, (fns, ids, locks))
    for i in range(nts): # Ждем завершения всех циклов преобразований датчиков
      while locks.locked(): pass
    return DS18B20.tsd
#-------------------------------------------------------------------------------
class BMP180(object):
  """  Класс-обертка для датчика атмосферного давления и температуры BMP180.
    Давления и температура представлены соответствущими свойствами (P и T)
    экземпляра класса. Чтение датчиков происходит при каждом использовании
    свойств в правой части выражения."""
  sensor = None
  def __new__(cls):
    """ Перед созданием объекта В методе __new__ производится проверка
        наличия и работоспособности датчика BMP180"""
    try:
      cls.sensor = bmp.BMP085()
      cls.sensor.read_pressure()
      cls.sensor.read_temperature()
      return super(BMP180, cls).__new__(cls)
    except:
      print "Датчик BMP180 отсутствует или неисправен"
      return None

  def __init__(self):
    self._sensor = BMP180.sensor
 
  @property
  def P(self):
    """Свойство - значение атмосферного давления в мм.рт.ст."""
    return self._sensor.read_pressure()/133.322 # Паскали -> в мм.рт.ст.

  @property
  def T(self):
    """Свойство - значение температуры датчика в градусах Цельсия."""
    return self._sensor.read_temperature()
#-------------------------------------------------------------------------------
class RMS(object):
  """    Класс-обертка для датчика среднеквадратичного напряжения сети.
    По умолчанию предполагается, что датчик подключен к 1-ой шине I2C
    по адресу 5 (можно изменить при создании объекта)."""
  def __new__(cls, addr = 0x05, bus = smbus.SMBus(1)):
    """Перед созданием объекта в методе __new__ производится
      тестирование датчика (наличие и работоспособность).
      addr - адрес датчика на шине I2C. По умолчанию - 5
      bus - шина (объект SMBus). По умолчанию - SMBus(1)"""
    try: # Проверим наличие и работоспособность датчика
      bus.read_byte(addr)
      # Все в порядке - создаем объект - датчик RMS
      return super(RMS, cls).__new__(cls)
    except:
      print "Датчик RMS отсутствует или неисправен"
      return None

  def __init__(self, addr = 0x05, bus = smbus.SMBus(1)):
    """addr - адрес датчика на шине I2C. По умолчанию - 5
      bus - шина (объект SMBus). По умолчанию - SMBus(1)"""
    self._addr = addr
    self._bus = bus

  @property
  def V(self):
    """Свойство - значение среднеквадратичного напряжения сети"""
    return self._bus.read_byte(self._addr) + 100
#-------------------------------------------------------------------------------
if __name__ == "__main__": # Тестирование классов модуля sens
  print "\nДатчики DS18B20"
  tsIDs = DS18B20.IDs() # Список ID всех датчиков DS18B20 на шине 1 Wire
  nts = len(tsIDs) # Количество датчиков DS18B20, обнаруженных на шине
  if nts == 0:
    print "Датчики DS18B20 не обнаружены"
  else:
    print "\nПоследовательный опрос %d датчиков" % (nts)
    st = time.time()
    for id in tsIDs:
      ts = DS18B20(id) # Создаем объект (датчик DS18B20)
      temperature = ts.T # Измеряем температуру этим датчиком
    print "%5.3f сек" % (time.time() - st)

    print "\nПараллельный запуск %d датчиков" % (nts)
    st = time.time()
    d = DS18B20.Ts() # Метод Ts() возвращает словарь с id датчиков (ключи) и
                    # температурой (значения)
    for id in d.keys():
      print "0x%012x :% 7.3f°C" % (id, d[id])
    print "%5.3f сек" % (time.time() - st)

  print "\nДатчик BMP180"
  bmp = BMP180()
  if bmp != None: # Датчик в наличии и функционирует
    print "Давление: \t%5.1f мм.рт.ст." % (bmp.P)
    print "Температура:\t%5.2f°C" % (bmp.T)

  print "\nДатчик RMS"
  vs = RMS()
  if vs != None: # Датчик в наличии и функционируе
    V = vs.V # Измеряем напряжение
    if V > 100: print "Среднеквадратичное напряжение: %d V" % (V)
    else: print "Слишком низкое напряжение в сети ( < 100B)"

  print "\nТест на наличие датчика DS18B20 с id = 0x1888888 :)"
  ts = DS18B20(0x1888888)
  if ts != None: print "Есть такой датчик!!!"

#-------------------------------------------------------------------------------
"""История изменений

25.01.2017
----------
1. Написана документация модуля
2. Практически полностью переписан класс-обертка DS18B20 и расширен его
  функционал - добавлена возможность выполнения цикла преобразования
  каждого датчика в параллельных потоках
3. Перед созданием объектов-датчиков (RMS и BMP180) добавлено их тестирование
  (наличие датчика и работоспособность интерфейса).

26.01.2017
----------
4. Перед созданием объект-датчика DS18B20 производится проверка его наличия
  на шине 1-Wire

"""
Этот и остальные файлы из комплекта nna_02.
OldBean Доцент Красноярск 1K 1.4K
Отв.1148  13 Февр. 18, 17:37
Спасибо, я понял какая у Вас версия. Но, похоже, у Вас проблемы с самими датчиками, а не со скриптами. Сами-то датчики система видит, но 3 из 4-х возвращают значение 85°C, которое присваивается при инициализации DS-ок. Это говорит о некорректной работе с датчиками. Наиболее вероятная причина - ошибки коммуникации малинки с этими тремя датчиками. Может быть помехи, а может - неисправности самих датчиков. Корректные значения иногда "прорываются".

Для фиксации проблемы проще воспользоваться средствами самой операционной системы для работы с датчиками, а не возиться со скриптами. В малинкиной директории /sys/bus/w1/devices/ должны быть четыре папки, названия которых совпадает с ID датчиков температуры (для DS-ок названия начинаются с "28-..."). Заходите в эти директории и ищите причину в файлах w1_slave. Это - тектовые файлы, в которых есть и диагностическая информация, и значения самих температур. Пока не добьетесь корректной работы датчиков (а именно - корректного содержимого файлов w1_slave) смысла возиться со скриптами нет. Так как методы класса-обертки DS18B20 (который описан в модуле sens) берут информацию как раз из этих файлов.

Смотрели? Что в этих файлах?

ZagAl Доцент Прибалтика 1.9K 916
Отв.1149  13 Февр. 18, 22:38
OldBean, вот:
2018-02-13-213303_815x516_scrot.png
2018-02-13-213303_815x516_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Или нужно запускать sens.py и если отображаются температуры 85.0 то тогда смотреть что в w1_slave?
На некоторое время отключил датчики и вновь подключил. Вот лог:
2018-02-13-221258_815x498_scrot.png
2018-02-13-221258_815x498_scrot. Ненавязчивая автоматизация ректификационной установки. Автоматика.

Что делать? Менять датчики?
OldBean Доцент Красноярск 1K 1.4K
Отв.1150  14 Февр. 18, 03:05
Что делать? Менять датчики?ZagAl, 13 Февр. 18, 22:38
Возможно, но я бы еще проверил. На всякий случай. Связь вроде нормальная, но, похоже, не запускается сам цикл преобразования. Если датчики без гильз, вытащите их и поставьте на питание (VCC-GND, подпаяйте прямо на ножки датчиков) керамические конденсаторы 0.1 мкФ. И потестируйте. Может быть им просто не хватает питания. Только запрашивайте не 1-2 раза, а много-много раз. Датчики должны работать безсбойно часами и сутками. Иначе никакая автоматизация толком работать не будет.
PS
Не покупайте дешевые датчики. "Левых" сейчас очень много. Не так давно взял (исключительно для пробы!) 4 недорогих датчика. Один всегда показывает 0, другой 127. Два других еще живы, но врут безбожно. Один показывает примерно градусов на 5 выше, второй - на 3. Вот так!
U-M Магистр MSK 210 39
Отв.1151  14 Февр. 18, 10:44
Не покупайте дешевые датчики. "Левых" сейчас очень много.OldBean, 14 Февр. 18, 03:05
На этом фоне - нет мысли применить PT100 в связке с МАХ31865. Главный минус - каждому датчику свой шлейф и своя МАХ...
ZagAl Доцент Прибалтика 1.9K 916
Отв.1152  14 Февр. 18, 11:09, через 26 мин
Только запрашивайте не 1-2 раза, а много-много раз.OldBean, 14 Февр. 18, 03:05
OldBean, Сергей, имеется ввиду цикл: включить, считать, выключить?
P.S. Всегда покупаю у продавцов с хорошим рейтингом, пусть даже подороже. В наличии имеются запасные. Поэтому для начала попробую сравнить их работоспособность. Но и ваш вариант тестирования тоже опробую.
m16 Модератор Тамбов 1.9K 1K
Отв.1153  14 Февр. 18, 11:34, через 26 мин
На этом фоне - нет мысли применить PT100U-M, 14 Февр. 18, 10:44
U-M, шестой год пользую менее сложную 8-ми канальную конфигурацию
OldBean Доцент Красноярск 1K 1.4K
Отв.1154  14 Февр. 18, 14:57
имеется ввиду цикл: включить, считать, выключить?ZagAl, 14 Февр. 18, 11:09
Не обязательно. Любой из скриптов, которые Вы приводили чуть выше, где нет "костылей" (т.е. пересброса датчиков датчиков). Задача - добиться чтобы датчики работали  без сбоев сколь угодно долго. Шина 1-Wire как у Вас устроена? Я имею в виду длину и топологию. Для начала сделайте все покороче и без ветвлений.

На этом фоне - нет мысли применить PT100 в связке с МАХ31865.U-M, 14 Февр. 18, 10:44
У DS-ок хорошее соотношение цена/качество. Если использовать Брезенхема для регулировки мощности и нет серьезных помех тут же рядом (типа электросварки ;), то с ними вообще никаких проблем нет. И быть не должно. Надо просто разобраться в источнике проблем у коллеги ZagAl. А те дешевенькие я взял специально из любопытства. Посмотреть как они работают. Ну посмотрел... ;)
ZagAl Доцент Прибалтика 1.9K 916
Отв.1155  14 Февр. 18, 16:04
Любой из скриптов, которые Вы приводили чуть выше, где нет "костылей"OldBean, 14 Февр. 18, 14:57
Сергей, так там и не было "костылей". Сбои я моделировал, отключая датчики вручную. На неработающей колонне, датчики работают без сбоев. Проверял. Почти сутки. Длина проводов 3 метра. Ну сейчас еще запущу четвертый вариант, тот, что сбои считает.
А вот на работающей колонне когда как. То выбивает датчики и довольно часто, то нет. В настоящее время экспериментирую на малых загрузках. Только для того чтобы посмотреть как колонна выходит на покапельный режим отбора голов и отбор голов с контролем веса и счетчика капель. Поэтому колонна в работе всего 2-3 часа.
 
202105.png
202105. Ненавязчивая автоматизация ректификационной установки. Автоматика.
log_250118.jpg
Log_250118. Ненавязчивая автоматизация ректификационной установки. Автоматика.

P.S. Может какие электромагнитные наводки возникают от ТЭНа? Хотя куб заземлен. Может заземление плохое?
makh Профессор Sаmara 2.1K 1.1K
Отв.1156  14 Февр. 18, 16:29, через 26 мин
ZagAl, если где-то в схеме устройства, или рядом, фигурирует один или несколько неизвестного происхождения импульсных блоков питания, попробуй менять по одному, и смотреть на реакцию железа. У мну такое было -- собираешь установку, все как обычно вроде, но откисает вся гирлянда градусников каждые пару минут. Методом исключения нашол китайский БП, который это делал. Пара одинаковых была, один на электронику и насосы, второй на воздушный деф, так вот когда глючный кормил вентиляторы проблемы не было, а когда электронику -- непонятной природы горе..
ZagAl Доцент Прибалтика 1.9K 916
Отв.1157  14 Февр. 18, 17:30
makh, я пользуюсь блоком питания от настольного компьютера. С него беру и 5 вольт и 12 (для шаговых двигателей).
PavelSaratov Доктор наук Саратов 622 80
Отв.1158  14 Февр. 18, 17:59, через 30 мин
А те дешевенькие я взял специально из любопытства. Посмотреть как они работают. Ну посмотрел... Подмигивающий
Возникает вопрос - а где недешевенькие берете?
сообщение удалено
OldBean Доцент Красноярск 1K 1.4K
Отв.1159  14 Февр. 18, 19:21
так там и не было "костылей". Сбои я моделировал, отключая датчики вручную.ZagAl, 14 Февр. 18, 16:04
А... А я-то думал, что Вы автоматизировали перезагрузку датчиков (тексты смотрел только у первых скриптов, но по скриншотам стало ясно, что проблема в датчиках, а не в скриптах).
На неработающей колонне, датчики работают без сбоев. Проверял. Почти сутки. ... А вот на работающей колонне когда как. То выбивает датчики и довольно часто, то нет.ZagAl, 14 Февр. 18, 16:04
Тогда, с большой вероятностью, что наводки, а источник помех явно связан с установкой. Нужно искать. Про метод исключения коллега makh уже рассказал ;) Это действенный метод.

Кстати, отличная у Вас ложечка получилась! А я для аналогичной задачи (измерение расхода) хотел 100-грамовые тензовесы приспособить и сосуд с сифоном для периодического слива.

Возникает вопрос - а где недешевенькие берете?PavelSaratov, 14 Февр. 18, 17:59
В том же магазине, что и дешевые. Только цена в два (с небольшим гаком) раза поболее. Они работают нормально и, кстати, очень хорошо коррелируют с датчиками из совсем старой партии, которую я брал еще лет 10 назад