a
    ign                     @   s   d Z ddlZddlZddlZddlZddlmZmZmZm	Z	m
Z
 G dd dZeedddZd	d
 ZddddZedkre  dS )uB#  
PCA9685 - ШИМ модуль. 
- I2C интерфейс
- I2C адрес: 0x40 (заводское значение). Изменяется путем пайки перемычек.
- Питание модуля: 3,3 В или 5 В
- Питание чипа: (VCC) 2,3 … 5,5 В постоянного тока
- Потребляемый ток: 
	… 10 мА в рабочем режиме (номинально 6мА)
	… 15,5 мкА в режиме ожидания (номинально 2,2мкА)
- Ток нагрузки на выходах: 
	… 25 мА при VCC = 5В и выходом с открытым стоком (флаг OUTDRV=0)
	… 10 мА при VCC = 5В и каскадным выходом чипа (флаг OUTDRV=1)
- Частота тактирования: 
	25 МГц внутренний генератор (±3%)
	0 … 50 МГц внешний источник тактирования
- Количество каналов ШИМ: 16 шт. с поддержкой «горячего» подключения устройств к выходам
- Разрешение ШИМ: 12 бит 4096 тактов (рабочий цикл от 0 до 100%)
- Выходная частота ШИМ: 24 … 1526 Гц для внутреннего генератора 25 МГц (зависит от частоты тактирования и значения предделителя)
- Datasheet: https://micro-pi.ru/wp-content/uploads/2018/03/PCA9685_ru.pdf

	Назначение: 
		Установка ШИМ - значения для портов микросхемы.
	Возможности:
		1. Использование как класса, используемого приложением
		2. Использование как самостоятельного приложения
	Синтаксис:
		pca9685.py [--uid] [--bus] [-a address] [-f frequency 24...1526] [-c channel [0 - 15]] [-s state 0 < nn < 100}] [-o output {text|json}]
		где:
			--uid       	- 	Уникальный идентификатор. 
								Параметр не обязательный. 
								В коде никак не обрабатывается.
								Предназначен скорее для источника, запросившего данные с датчика, может быть использован 
								при синхронном запросе в источнике и последующей обработке результата в источнике.
			--bus			-   Номер шины I2C на Raspberry Pi. 
								Параметр не обязательный.
								Допускается следующий формат:
									- параметр не указан - по умолчанию номер шины = 0
									- 0|1 - номер шины. 
			-a address 		- 	I2C адрес на котором расположена микросхема pca9685. 
								Параметр не обязательный.
								Допускается следующий формат:
									- параметр не указан - будет установлено значение по умолчанию, в соответствии 
									с установленным ADDRESS;
									- адрес в десятичном или шестнадцатеричном представлении.
			-f frequency	- 	Частота в Hz. 
								Параметр не обязательный
								Допускается следующий формат:
									- параметр не указан - будет установлено значение по умолчанию, в соответствии 
									с установленным FREQUENCY;
									- целое число в диапазоне от 24 Hz до 1526 Hz.
			-c channel		- 	Список каналов, для которых необходимо установить величину импульса. 
								Параметр не обязательный
								Допускается следующий формат:
									- параметр не указан - будут установлены значения всех каналов микросхемы
									- список каналов, разделенных пробелом - будут установлены значения для 
									перечисленных каналов. Допускается указание как в шестнадцатеричном, так и в десятичном представлении.
								Возможна любая комбинация из обозначений каналов, 
								например: -c 0 0x07 0x0A 15 - будут отработаны каналы с номерами 0, 7, 10 и 15
			-s state		- 	Состояние уровня канала. 
								Параметр не обязательный.
								Допускается следующий формат:
									- параметр не указан - будут возвращены текущие значения указанных channel каналов в процентах,
									- от 0 до 100 - установка канала в состояние от 0 до 100 процентов (знак процента не ставится), 
									где 0 - это выключенное состояние, 100 - включено на максимум
			--duration		- 	Длительность плавного перехода секундах. 
								Параметр не обязательный.
								Допускается следующий формат:
									- параметр не указан - плавного перехода не будет.
									- число с плавающей запятой, в сек. - в течении указанного времени бужет плавное изменение занчения от текущего, 
									для каждого канала, до указанного значения.
								Плавное изменение работает только тогда, когда заданы оба параметра: duration и steps
			--steps			- 	Количество шагов для плавного перехода.
								Параметр не обязательный.
								Допускается следующий формат:
									- параметр не указан - плавного перехода не будет.
									- целое число - количество шагов в течении duration секунд
								Плавное изменение работает только тогда, когда заданы оба параметра: duration и steps
			-o output		- 	Тип результата. 
								Параметр не обязательный.
								Допускается	следующий формат:
									- параметр не указан - тихий режим, без вывода результата
									- text - тип text
									- json - тип json

	Ответ в формате:
	json 
		{
			status: код ответа от сервиса (например 200 - ок|400 - не коррекнтый запрос|520 - неизвестная ошибка| и т.д.)
			message: описание ответа
			request: {
				uid: уникальный идентификатор
				bus: номер I2C шины 		
				address: адрес на котором расположен шим-контроллер pca9685.
				frequency: частота в Hz.
				channel: [cписок каналов, для которых необходимо установить ШИМ]
				state: состояние канала
				duration: длительность плавного перехода
				steps: количество шагов для плавного перехода
				output: тип результата
			}
			response: [{
				channel: номер канала
				state: величина ШИМ - сигнала
			}]
		}                                                    
	text
		status<код ответа> - <описание ответа>
		uid<уникальный идентификатор> bus<номер I2C шины> address<адрес> frequency<частота Hz> channel<cписок каналов, разделенный запятыми> state<состояние канала> duration<длительность плавного перехода> steps<количество шагов для плавного перехода> output<тип результата>
		channel<номер канала> state<величина ШИМ - сигнала>
		...
		channel<номер канала> state<величина ШИМ - сигнала>

	Модуль написан в 2025 году.
	Основой для создания модуля послужила статья 
	https://github.com/adafruit/Adafruit_Python_PCA9685
    N)AnyOptionalListDictUnionc                   @   sb  e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdZdZdZdZdZdZdZdeefeeeddddZd7eddddZefeddddZddddZddddZefedd d!d"Zeeedd#d$d%Zeedd&d'd(Zeeee e f  e!dd)d*d+Z"d8eeee e f  ee!edd.d/d0Z#eed1d2d3Z$eeee e f  e%d4d5d6Z&dS )9PCA9685z0.2@   2   r                  	                     N)i2caddress	frequencyreturnc                 C   s   || _ || _|| _d S N)i2cbusr   r   )selfr   r   r    r   //var/aqua_controller/devices/pca9685/pca9685.py__init__   s    zPCA9685.__init__)r   r   c                 C   s
   || _ d S r   )r   )r   r   r   r   r   set_i2c   s    zPCA9685.set_i2c)r   r   c                 C   s
   || _ d S r   )r   )r   r   r   r   r   set_address   s    zPCA9685.set_addressr   c              
   C   sX   z$| j | j| j| j td W n. tyR } ztd|W Y d }~n
d }~0 0 d S )N{Gzt?u^   Ошибка при сбросе устройства в начальное состояние)	r   write_byte_datar   MODE1SLEEPtimesleep	ExceptionIOError)r   er   r   r   reset   s
    zPCA9685.resetc              
   C   s   z| j | j| j| j | j | j| j| j td | j 	| j| j}|| j
 @ }| j | j| j| td | | j W n. ty } ztd|W Y d }~n
d }~0 0 d S )Nr#   uC   Ошибка при инициализации устройства)r   r$   r   MODE2OUTDRVr%   ALLCALLr'   r(   read_byte_datar&   set_pwm_frequencyr   r)   r*   )r   Zmode1r+   r   r   r   run   s    

zPCA9685.run)r   r   c              
   C   s  zd|  krdks n t d|| _d}|d }|t| j }|d8 }tt|d }| j| j| j	}|d@ d	B }| j
| j| j	| | j
| j| j| | j
| j| j	| td
 | j
| j| j	|dB  W n0 ty } ztd|W Y d }~n
d }~0 0 d S )N   i  ug   Частота ШИМ может быть установлена в диапазоне 24 – 1526 Гцg    wAg      @      ?g      ?   r   r#      u<   Ошибка при установке частоты ШИМ)
ValueErrorr   floatintmathfloorr   r0   r   r%   r$   PRESCALEr'   r(   r)   RuntimeError)r   r   ZprescalevalZprescaleZold_modeZnew_moder+   r   r   r   r1      s$    
zPCA9685.set_pwm_frequency)channelonoffr   c              
   C   s  zd|  krdks n t dd|  kr4dks>n t dd|  krRdks\n t d| j| j| jd|  |d@  | j| j| jd|  |d	?  | j| j| jd|  |d@  | j| j| jd|  |d	?  W n6 ty } zt	d
| |W Y d }~n
d }~0 0 d S )Nr      e   Номер канала может быть установлен в диапазоне от 0 до 15  o   Время включения может быть установлено в диапазоне от 0 до 4095q   Время выключения может быть установлено в диапазоне от 0 до 4095r      r   ud   Ошибка при установке величины ШИМ - сигнала для канала )
r7   r   r$   r   	LED0_ON_L	LED0_ON_H
LED0_OFF_L
LED0_OFF_Hr)   r=   )r   r>   r?   r@   r+   r   r   r   set_pwm   s       $zPCA9685.set_pwm)r?   r@   r   c              
   C   s   zd|  krdks n t dd|  kr4dks>n t d| j| j| j|d@  | j| j| j|d?  | j| j| j|d@  | j| j| j|d?  W n. ty } zt	d|W Y d }~n
d }~0 0 d S )Nr   rC   rD   rE   rF   r   un   Ошибка при установке величины ШИМ - сигнала для всех каналов)
r7   r   r$   r   ALL_LED_ON_LALL_LED_ON_HALL_LED_OFF_LALL_LED_OFF_Hr)   r=   )r   r?   r@   r+   r   r   r   set_all_pwm   s    zPCA9685.set_all_pwm)channelstarget_percentr   c              
   C   s   zd|  krdks n t d|d ur`t|tr8|g}|D ]"}d|  krTdks<n t dq<t|d d }|d ur|D ]}| |d| q|n| d| W n. ty } ztd|W Y d }~n
d }~0 0 d S )Nr   d   z   Величина ШИМ - сигнала (в процентах) может быть в диапазоне от 0 до 100rA   R   Номер канала должен быть в диапазоне от 0 до 15rC   u7   Ошибка установки величины ШИМ)r7   
isinstancer9   rK   rP   r)   r=   )r   rQ   rR   item_channelvaluer+   r   r   r   set_pwm_percent  s     

zPCA9685.set_pwm_percentr4   rS   )rQ   rR   durationstepsr   c                 C   s  zd|  krdks"n t d|dkr2t d|dkrBt d|d u rXttd}nt|trh|g}|D ]"}d|  krdksln t dqlg }|D ]H}| |}|d	 d }t|| d
k rq|| | }	||||	f q|sW d S || }
t	 }t|D ]}t	 }||d |
  }|D ]b\}}}	z ||	|d   }| 
|| W n4 ty } zW Y d }~q$W Y d }~n
d }~0 0 q$t	 |k rqqW n0 ty } ztd|W Y d }~n
d }~0 0 d S )Nr   rS   rT   ug   Длительность перехода в секундах должна быть более нуляur   Количество шагов для плавного перехода должно быть более нуляr   rA   rU   rC   g?r
   u.   Ошибка плавного перехода)r7   listrangerV   r9   get_pwmabsappendr'   	monotonicrY   r)   r=   )r   rQ   rR   rZ   r[   rW   Zchannels_stepsZcurrent_valueZcurrent_percentstepdelay
start_timeicurrent_timeZtarget_timeZnum_channelcurrentZnew_percentr+   r   r   r   set_pwm_percent_smooth!  sN    


(zPCA9685.set_pwm_percent_smooth)r>   r   c              
   C   s   z`d|  krdks n t d| j| j| jd|  }| j| j| jd|  }|d> |B W S  ty } ztd| |W Y d }~n
d }~0 0 d S )Nr   rA   rB   r   r   uW   Ошибка чтения значения ШИМ - сигнала для канала )r7   r   r0   r   rI   rJ   r)   r=   )r   r>   Zoff_lZoff_hr+   r   r   r   r^   X  s    zPCA9685.get_pwm)rQ   r   c              
   C   s   i }z|d u rt td}nt|tr,|g}|D ]"}d|  krHdks0n tdq0|D ]J}| |}d|  krzdkrn n|d d }t|d||< qXd ||< qX|W S  ty } ztd|W Y d }~n
d }~0 0 d S )	Nr   r   rA   rU   rC   rS      uJ   Ошибка получения величины ШИМ - сигнала: )	r\   r]   rV   r9   r7   r^   roundr)   r=   )r   rQ   resultrW   Z
tmp_resultZtmp_percentr+   r   r   r   get_pwm_percente  s$    



zPCA9685.get_pwm_percent)N)r4   rS   )'__name__
__module____qualname__VERSIONADDRESSZ	FREQUENCYr%   r-   r<   rG   rH   rI   rJ   rL   rM   rN   rO   r.   r/   r&   r   r9   r   r    r!   r,   r2   r1   rK   rP   r   r   r   r8   rY   rh   r^   r   rl   r   r   r   r   r      s:   "(7r   )rX   r   c                 C   s6   zt | dW S  ty0   td|  dY n0 d S )Nr   #   Неверное значение: u+   . Ожидается целое число.)r9   r7   argparseArgumentTypeErrorrX   r   r   r   __fn_to_int  s    rv   c                 C   s4   z
t | W S  ty.   td|  dY n0 d S )Nrr   uE   . Ожидается число с плавающей запятой.)r8   r7   rs   rt   ru   r   r   r   __fn_to_float  s    
rw   r"   c               
   C   sJ  d} d}i }zt jdd}|jdtdd dd |jd	tdd
dd |jddtdd dd |jddtdd dd |jddtddd dd |jddtdd dd |jdtdd dd |jdtdd dd |jddtdd d!gd d"d# | }W n6 t jy  } zd$} d%| }W Y d }~n
d }~0 0 zd
d l}|	|j
}W nH ty } z.d&} d'|j
 d(t|j d)| }W Y d }~n
d }~0 0 | dkrzLt }|| |jd ur||j |jd ur||j |  W n@ ty } z&d*} d+t|j d)| }W Y d }~n
d }~0 0 | dkr |jd ur |jd ur|jd urz||j|j|j|j W n@ ty } z&d*} d,t|j d)| }W Y d }~n
d }~0 0 nVz||j|j W n@ ty } z&d*} d-t|j d)| }W Y d }~n
d }~0 0 | dkr\z||j}W n@ tyZ } z&d*} d.t|j d)| }W Y d }~n
d }~0 0 |d urz|  W n@ ty } z&d/} d0t|j d)| }W Y d }~n
d }~0 0 z8|jd ur~|j d kr~ }	|	d1t|  d2t| d37 }	|	|jd urd4t|j d5nd67 }	|	|j
d ur<d7t|j
 d5nd67 }	|	|jd urbd8t |j d5nd67 }	|	|jd urd9|j d5nd67 }	|	|jd urd:d;!t"t|j d5nd67 }	|	|jd urd<|j d5nd67 }	|	|jd urd=|j d5nd67 }	|	|jd urd>|j d5nd67 }	|	|jd ur>d?t|j d5nd67 }	|	d@7 }	|D ]$}
|	d:|
 dAt||
  d37 }	qPt#|	 |jd ur|j d!kri }	| |	dB< t||	dC< i |	dD< |jd urt|j|	dD dE< |j
d ur|j
|	dD dF< |jd urt |j|	dD dG< |jd ur*|j|	dD dH< |jd urD|j|	dD dI< |jd ur^|j|	dD dJ< |jd urx|j|	dD dK< |jd ur|j|	dD dL< |jd ur|j|	dD dM< g |	dN< |D ]}
|	dN $|
||
 dO qt#t%j&|	ddPdQ W nV tyD } z<d/} dRt|j d)| }t#d1|  d2| dS W Y d }~n
d }~0 0 d S )TN   oku,   Управление PCA9685 через I2C.)descriptionz--uidFu>   Уникальный идентификатор запроса)typerequireddefaulthelpz--busr   uE   Номер шины I2C на Raspberry Pi (по умолчанию 0)z-az	--addressu    Адрес ШИМ - модуляz-fz--frequencyu$   Частота ШИМ - модуляz-cz	--channel*u-   Номер канала ШИМ - модуля)r{   r|   nargsr}   r~   z-sz--stateu$   Состояние ШИМ (0 - 100%)z
--durationu=   Длительность плавного в секундахz--stepsuH   Количество шагов для плавного переходаz-oz--outputtextjsonu+   Формат вывода: text или json)r{   r|   choicesr}   r~   i  uA   ошибка обработки командной строки: i  u   i2c шина u    недоступна: z => i  u>   Ошибка инициализации устройства: u[   Ошибка плавного изменения величины ШИМ - сигнала: uJ   Ошибка изменения величины ШИМ - сигнала: uD   Ошибка чтения величины ШИМ - сигнала: i  u1   не удалось закрыть шину i2c: zstatus<z> - <z>
zuid<z>  zbus<zaddress<z
frequency<zchannel<,zstate<z	duration<zsteps<zoutput<
z> state<statusmessagerequestuidbusr   r   r>   staterZ   r[   outputresponse)r>   r   ri   )ensure_asciiindentu4   Ошибка формирования ответа: >)'rs   ArgumentParseradd_argumentstrrv   rw   
parse_argsArgumentErrorsmbusSMBusr   r)   r{   rm   r   r    r   r!   r   r1   r2   r   rZ   r[   rh   r>   rY   rl   closer   lowerr   hexjoinmapprintr`   r   dumps)_status_status_message_resultparserargsr+   r   my_i2cZ
my_PCA9685	_response_item_resultr   r   r   main  s     4

,
.,
,
,&&&"."""&"r   __main__)__doc__rs   r:   r'   r   typingr   r   r   r   r   r   r   r9   rv   rw   r   rm   r   r   r   r   <module>   s   u  	 