ZigBee на Raspberry, часть 2, установка софта

Итак, в первой части мы прошили стикер CC2531, теперь наша малинка готова стать шлюзом. Обычно схема работы Raspberry следующая:

ZigBee2MQTT — нужен для того чтобы принять пакеты со стика CC2531 и отправить их в брокер сообщений. Которые в дальнейшем уже обработают скрипты для автоматизации чего-либо.

Сначала поставим брокер сообщений mosquitto (как самое легкое):

sudo apt-get install mosquitto

И настроим файл конфигурации /etc/mosquitto/mosquitto.conf :

pid_file /run/mosquitto/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
include_dir /etc/mosquitto/conf.d
allow_anonymous true   # доступ для всех
listener 1883 0.0.0.0  # слушаем все сетевые адреса

Можно задать логин пароль для доступа, и разрешить слушать только localhost, но я это считаю излишним, т.к. всё равно чаще всего raspberry pi лежит в локальной сети и в интернет не смотрит. Далее включаем службу и стартуем её:

sudo systemctl enable mosquitto
sudo systemctl restart mosquitto

Теперь ставим и настраиваем ZigBee2MQTT. Можно по туториалу на сайте разработчиков, а можно так, как описано ниже (без подробностей).

sudo apt-get install nodejs git
corepack enable
sudo mkdir /opt/zigbee2mqtt
sudo chown -R ${USER}: /opt/zigbee2mqtt
git clone --depth 1 https://github.com/Koenkk/zigbee2mqtt.git /opt/zigbee2mqtt
cd /opt/zigbee2mqtt
pnpm install --frozen-lockfile
cd /opt/zigbee2mqtt
pnpm start

После успешного старта будет доступен веб интерфейс для дальнейшей настройки в браузере http://ip:8080. Необходимо зайти, выбрать порт где расположен стик, и ввести данные для подключения к брокеру. После сохранить. Конфиг будет сохранен в /opt/zigbee2mqtt/data/configuration.yaml

Далее оформим запуск ZigBee2MQTT как службу, создав и сохранив файл:

[Unit]
Description=zigbee2mqtt
After=network.target

[Service]
Environment=NODE_ENV=production
Type=notify
ExecStart=/usr/bin/node index.js
WorkingDirectory=/opt/zigbee2mqtt
StandardOutput=inherit
# Or use StandardOutput=null if you don't want Zigbee2MQTT messages filling syslog, for more options see systemd.exec(5)
StandardError=inherit
WatchdogSec=10s
Restart=always
RestartSec=10s
User=pi

[Install]
WantedBy=multi-user.target
sudo systemctl enable zigbee2mqtt
sudo systemctl start zigbee2mqtt

Ну и теоретически всё. По идее можно подключать устройства zigbee. В следующей части собственно это и рассмотрю.

ZigBee на Raspberry, часть 1, прошивка CC2531

Задача: научится принимать пакеты по протоколу Zigbee на устройстве Raspberry PI 3. Сама по себе, без внешних дополнительных устройств, Raspberry этого не умеет. Нужен модем, который может принимать сигналы на этой частоте. Для этого было куплено на Aliexpress устройство Zigbee CC2531. Покупателю оно приходит пустое, без прошивки, поэтому перед работой с ним, его необходимо прошить. Есть несколько вариантов, самый простой сделать это при помощи самой же RaspberryPI. Одно Но! (и даже их несколько):

  • нужно делать самому подключение проводками
  • на модеме ножки очень тонкие, и стандартные проводки от Arduino например не подойдут. Я городил огород при помощи малярного скотча, а кто-то отгибал ножки и припаивался к ним на прямую.

Общая схема подключения для прошивки следующая:

После того как наколхозите этот переходник, можно начинать прошивку. Но сначала убедимся, что модем вообще виден в системе, выполнив команду lsusb. Должно выйти что-то вроде:

Если всё ок, двигаемся к следующему шагу: скачиваем утилиту для прошивки:

git clone https://github.com/jmichault/flash_cc2531.git
cd flash_cc2531
./cc_chipid

И скорее всего получим фигу вида:

root@raspberrypi:/home/donpadlo/flash_cc2531# ./cc_chipid
bash: ./cc_chipid: cannot execute: required file not found

Я подозреваю, что этой утилите не хватает библиотеки wiringPi. Установить её можно так:

git clone https://github.com/WiringPi/WiringPi.git
cd WiringPi
 ./build

И далее снова попробовать выполнить :

./cc_chipid

И я снова получил туже самую ошибку. Ну чтож..попробуем собрать банарник из исходных годов сами:

cd flash_cc2531
make

После чего, команда уже выполнится корректно:

./cc_read
ID = b534

Т.е. устройство прошивальщик теперь видит. Скачаем последнюю версию прошивки (можно прям по этой ссылке, т.к. версии более не разрабатываются для этого модема):

wget https://github.com/Koenkk/Z-Stack-firmware/raw/refs/heads/master/coordinator/Z-Stack_3.0.x/bin/CC2531_20190425.zip
unzip CC2531_20190425.zip
./cc_erase 
./cc_write CC2531ZNP-with-SBL.hex

И собственно всё. Теперь стик рабочий. Осталось научится получать с него данные. А это уже в следующих частях..

1С: таблица значений на форме

Задача: скрыть отдельную колонку или показать все колонки в таблице значений расположенной на форме.

Решение: напишем две процедуры, одна из которых скрывает текущую выбранную мышкой колонку, а другая показывает все колонки в выбранной таблице.

&НаКлиенте
Процедура СкрытьКолонку(Команда)
      ТЭ_имя_объект=ТекущийЭлемент.Имя;
      ТЭ_поле=ТекущийЭлемент.ТекущийЭлемент.имя;
      имяКолонки=СтрЗаменить( ТЭ_поле,ТЭ_имя_объект,"");	  
	  элементы[ТЭ_поле].Видимость=Ложь;
КонецПроцедуры

&НаКлиенте
Процедура ПоказатьВсеКолонки(Команда)
      ТЭ_имя_объект=ТекущийЭлемент.Имя;
      ТЭ_поле=ТекущийЭлемент.ТекущийЭлемент.имя;
      имяКолонки=СтрЗаменить( ТЭ_поле,ТЭ_имя_объект,"");
	  для каждого стр из элементы[ТЭ_имя_объект].ПодчиненныеЭлементы цикл
		  стр.Видимость=Истина;
	  конеццикла;	  
КонецПроцедуры

Функционал можно например навесить на контекстное меню

1С: Сжимаем прикрепленные файлы

Задача: есть некий справочник, к которому прикрепляются файлы. Физически они конечно хранятся в томах, но всё равно занимают места очень порядочно. Необходимо собственно каждый файлик положить в архив, заново «перекрепить» его к элементам справочника. Оригинал соответственно удалить.

Решение:

	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ ПЕРВЫЕ 1000
		|	Файлы.ВладелецФайла КАК ВладелецФайла,
		|	Файлы.Ссылка КАК Ссылка,
		|	Файлы.ПолноеНаименование КАК ПолноеНаименование,
		|	Файлы.ТекущаяВерсияПутьКФайлу КАК ПутьКФайлу,
		|	Файлы.ТекущаяВерсияТом.ПолныйПутьWindows КАК ПолныйПуть,
		|	Файлы.ДатаСоздания КАК ДатаСоздания
		|ИЗ
		|	Справочник.Файлы КАК Файлы
		|ГДЕ
		|	Файлы.ВладелецФайла ССЫЛКА Справочник.СК_ГосуслугиЛК_ВходящиеСообщения
		|	И Файлы.ПометкаУдаления = ЛОЖЬ
		|	И НЕ Файлы.ТекущаяВерсияПутьКФайлу ПОДОБНО ""%zip%""
		|	И Файлы.ДатаСоздания МЕЖДУ &ДатаС И &ДатаПо
		|
		|УПОРЯДОЧИТЬ ПО
		|	ДатаСоздания";	
	Запрос.УстановитьПараметр("ДатаС", объект.ДатаС);	
	Запрос.УстановитьПараметр("ДатаПо", объект.ДатаПо);	
	РезультатЗапроса = Запрос.Выполнить();	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		если СтрНайти(ВыборкаДетальныеЗаписи.ПутьКФайлу,".zip")=0 тогда
			НовыйАрхив = Новый ЗаписьZipФайла(
			        ВыборкаДетальныеЗаписи.ПолныйПуть+"tmp.zip",
			        "","",МетодСжатияZIP.Сжатие,УровеньСжатияZIP.Максимальный,МетодШифрованияZIP.Zip20					
			);			
			НовыйАрхив.Добавить(ВыборкаДетальныеЗаписи.ПолныйПуть+ВыборкаДетальныеЗаписи.ПутьКФайлу);
			НовыйАрхив.Записать();            
			//возврат 0;
			ДвоичныеДанные = Новый ДвоичныеДанные(ВыборкаДетальныеЗаписи.ПолныйПуть+"tmp.zip"); 
			АдресФайлаВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанные);
			РаботаСФайламиВызовСервера.СоздатьФайлСВерсией(
				ВыборкаДетальныеЗаписи.ВладелецФайла,
				ВыборкаДетальныеЗаписи.ПолноеНаименование+".zip",
				"zip",
				ТекущаяДата(),
				ТекущаяДата(),
				,
				АдресФайлаВХранилище,АдресФайлаВХранилище,
				Ложь,
				,
				,
				Истина
			);						
			об=ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
			об.ПометкаУдаления=Истина;
			об.Записать();
			об.Удалить();					
			УдалитьФайлы(ВыборкаДетальныеЗаписи.ПолныйПуть+ВыборкаДетальныеЗаписи.ПутьКФайлу);						
		конецесли;		
	КонецЦикла;

Т.е. что тут делаем: выбираем элемент справочника с прикрепленным файлом, сжимаем его в архив zip, прикрепляем его и удаляем оригинал.

1С: Сортировка таблицы значений на управляемой форме

По умолчанию, не понятно почему на платформе не завезено средство сортировки таблицы значений отображаемой на форме. Поэтому выходом может быть например такое решение:

  • добавляем команды СортироватьПоКолонкеВозр и СортироватьПоКолонкеУбыв
  • добавляем их в контекстное меню
  • Код команды может быть такой:
&НаКлиенте
Процедура СортироватьПоКолонке(Команда)
      ТЭ_имя_объект=ТекущийЭлемент.Имя;
      ТЭ_поле=ТекущийЭлемент.ТекущийЭлемент.имя;
      имяКолонки=СтрЗаменить( ТЭ_поле,ТЭ_имя_объект,"");
      если команда.имя="СортироватьПоКолонкеУбыв" тогда
           СортироватьНасервере(ТЭ_имя_объект,имяКолонки,"Убыв");
	  конецесли;		   
      если команда.имя="СортироватьПоКолонкеВозр" тогда
          СортироватьНасервере(ТЭ_имя_объект,имяКолонки,"Возр");
	конецесли;
КонецПроцедуры

&НаСервере
Процедура сортироватьНасервере(имяОбъекта,имяКолонки,ВидСортировки)
    тз= РеквизитФормыВЗначение("БуферТЗ");
    тз.Сортировать(имяКолонки+" "+ВидСортировки);
    ЗначениеВРеквизитФормы(ТЗ,"БуферТЗ");
конецпроцедуры

В результате получаем что-то подобное:

1 2 3 299