msgbartop
Me encanta el olor del napalm por la mañana
msgbarbottom

25 ene 20 Integración de una estación meteorológica doméstica en el sistema de domótica

Estas Navidades me han regalado una estación meteorológica casera, de las que tienen capacidad para mostrar temperatura y humedad tanto en interior como en exterior, esto último mediante un módulo externo que se deja a la intemperie, y que transmite la información a la estación mediante señal de radio a 433 MHz. Aparte de por el regalo en sí, este tipo de estaciones me venía interesando desde hace bastante tiempo por el hecho de enviar la información utilizando la banda antes mencionada, de la que dispongo unos cuantos receptores. Así que en cuanto abrí el regalo supe que iba a invertir algo de tiempo en intentar integrar el sensor externo en mi sistema de domótica.

Mi nueva estación meteorológica

Mi nueva estación meteorológica

Tras investigar un poco sobre este tipo de estaciones, encontré que la mayoría de ellas hacen uso de protocolos de comunicación bien definidos y relativamente estandarizados, lo que hace que sea razonablemente sencillo encontrar información sobre las mismas, e incluso implementaciones de dichos protocolos para entornos linux o arduino. Dicho lo cual, empecé a hacer algunas pruebas de implementación de un sistema que permitiera recibir la información del emisor externo. Las primeras pruebas las hice con un receptor basado en arduino y un módulo 433 MHz, más la librería rc-switch que tan buenos resultados me había dado en el pasado. No fue este el caso, ya que al intentar capturar paquetes enviados por la estación el programa de captura de paquetes basados en esta librería producía un error de desbordamiento, siendo incapaz de recibir correctamente el datagrama. Hice algunas pruebas en bruto con otras librerías, entre las que se incluían algunas diseñadas específicamente para alguno de los protocolos de envío antes mencionados, con resultados igualmente infructuosos.

NodeMCU con receptor a 433 MHz y módulo externo de la estación

NodeMCU con receptor a 433 MHz y módulo externo de la estación

Ante ello, no me quedó más remedio que cambiar el enfoque. Tocaba acometer el problema desde una perspectiva más basica. Así que me tocó desempolvar un receptor RTL SDR que compré hace algún tiempo para un proyecto similar, e intentar hacer una captura del datagrama a nivel de onda enviada, e intentar decodificar la misma (tirando para ello de programas como Gqrx, audacity, y algo de tiempo. Sin embargo, tuve algo de suerte, y tras seguir investigando un poco más, encontré una referencia a un proyecto, rtl_433, que se dedica a decodificar el tráfico de dispositivos que envían información en esta banda.

Captura de pantalla de rtl_433 capturando tráfico

Captura de pantalla de rtl_433 capturando tráfico

Tras una instalación sencilla en mi equipo con Debian (apt install rtl_433), y tras conectar el receptor RTL SDR al mismo, tuve la suerte de que el programa tuviera perfectamente identificado el tipo de protocolo que mi estación estaba utilizando, en concreto el protocolo “Kedsum Temperature & Humidity Sensor, Pearl NC-7415″. Trasteando un poco con el programa, pude tener algo más de información sobre este protocolo, a saber:

Frame structure:
Byte: 0 1 2 3 4
Nibble: 1 2 3 4 5 6 7 8 9 10
Type: 00 IIIIIIII BBCC++++ ttttTTTT hhhhHHHH FFFFXXXX
- I: unique id. changes on powercycle
- B: Battery state 10 = Ok, 01 = weak, 00 = bad
- C: channel, 00 = ch1, 10=ch3
- + low temp nibble
- t: med temp nibble
- T: high temp nibble
- h: humidity low nibble
- H: humidity high nibble
- F: flags
- X: CRC-4 poly 0×3 init 0×0 xor last 4 bits

_Modulation = OOK_PULSE_PPM,
-Short_width = 2000,
-Long_width = 4000,
-Gap_limit = 4400,
-Reset_limit = 9400,

Bien, ya tenía identificado claramente el protocolo, y aquí puede verse una captura de la señal recibida:

root@asustinker:/etc/systemd/system# /usr/local/bin/rtl_433 -R 57
rtl_433 version 19.08-147-g639ab8a branch master at 202001210044 inputs file rtl_tcp RTL-SDR
Use -h for usage help and see https://triq.org/ for documentation.

Consider using “-M newmodel” to transition to new model keys. This will become the default someday.
A table of changes and discussion is at https://github.com/merbanan/rtl_433/pull/986.

Registered 1 out of 145 device decoding protocols [ 57 ]
Found Rafael Micro R820T tuner
Exact sample rate is: 250000.000414 Hz
[R82XX] PLL not locked!
Sample rate set to 250000 S/s.
Tuner gain set to Auto.
Tuned to 433.920MHz.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
time : 2020-01-25 15:24:00
model : Kedsum Temperature & Humidity Sensor ID : 226
Channel : 1 Battery : OK Flags2 : 129 Temperature: 60.20 F Humidity : 78 % Integrity : CRC
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

Bien, esto me planteaba dos problemas: el primero es que la información recibida de temperatura estaba expresada en grados Fahrenheit, por lo que necesitaba hacer una conversión a Celsius. Y por otro lado, el poder transmitir esta información a mi plataforma de domótica, preferentemente a través de MQTT. Este segundo problema quedó solucionado mediante la capacidad del programa rtl_433 de encapsular la información en un JSON, que puede ser retransmitido posteriormente. En mi caso, lo hice mediante un servicio linux que lanza el programa rtl_433 con las opciones adecuadas (formato JSON, protocolo 57 -Kedsum-, e incrustando la hora UTC), que mediante un pipe es procesado por el cliente MQTT mosquitto y enviado a mi servidor MQTT, a un topic específico:

“/usr/local/bin/rtl_433 -R 57 -F json -M utc | /usr/bin/mosquitto_pub -l -h servidor_mqtt -t topic”

…donde posteriormente es procesado gracias a Node Red, en el que se hace la conversión a Celsius, se obtiene también la sensación térmica, y se inyecta la información resultante en formato JSON en un topic específico:

var data=JSON.parse(msg.payload);
//Datagram example: {“time” : “2020-01-22 19:27:58″, “model” : “Kedsum Temperature & Humidity Sensor”, “id” : 226, “channel” : 1, “battery” : “WEAK”, “flags” : 66, “temperature_F” : 54.600, “humidity” : 79, “mic” : “CRC”}
temp_value=((data.temperature_F-32)*5/9).toFixed(2);
humidity=data.humidity;

HI = 0.5*(data.temperature_F + 61.0 + ((data.temperature_F-68.0)*1.2) + (humidity*0.094))
HIc = (((HI)-32)*5/9).toFixed(2); // converting to Celsius

var thing = {
temp: temp_value,
humidity: humidity,
heatindex: HIc
};
msg.payload=thing;

return msg;

…y el resultado de todo esto fue un… ¡exito! Pasé a conectar el receptor RTL SDR a mi Asus Tinker Board donde tengo implementado el sistema de domótica, con excelentes resultados. El sistema, emplazado en la segunda planta de casa, es capaz de recibir las señales del receptor externo emplazado en el patio.

Asus Tinker Board con receptor RTL SDR

Asus Tinker Board con receptor RTL SDR

Por otro lado, quedaba la integración en el sistema de domótica Home Assistant. En este caso, se trataba de alto tan simple como crear los nuevos sensores en base a la suscripción al topic MQTT de salida definido en el flujo Node Red. El resultado, como no podía ser menos, fue perfecto:

Información mostrada en Home Assistant de la estación meteorológica

Información mostrada en Home Assistant de la estación meteorológica

Gráfica de la información histórica recibida

Gráfica de la información histórica recibida

Este artículo podría haber quedado aquí, pero no me encontraba completamente satisfecho con el resultado, ya que me daba la impresión de que utilizar el receptor RTL SDR solo para este propósito era matar moscas a cañonazos. Mi idea originaria era usar un ESP8266 junto con un módulo RF de 433 Mhz para recibir estas señales, y decodificarlas en el mismo, para inyectar la información directamente en el servidor MQTT, y no tener que dar tantos saltos (RTL SDR -> JSON -> MQTT -> Node Red -> MQTT). No tuve éxito en encontrar una codificación del protocolo bajo el nombre de Kedsum, pero sí la tuve con Pearl NC-7415. Encontré un hilo en un foro de Arduino en alemán, que hablaba precisamente de ello: Dekodieren Temperatursensor von PEARL NC7427(NC7415) 433MHz. Gracias, Google Translate. :mrgreen:

En este hilo pude encontrar alguien que había decodificado exitosamente el protocolo, y que compartía el código. Lo descargué y lo probé y… ¡funcionaba perfectamente! Solo tuve que hacer una modificación menor para realizar la conversión de Fahrenheit a Celsius, calcular la sensación térmica, e inyectarlo en el topic MQTT (el original no hacía nada de esto, se limitaba a mostrar la información por pantalla). Y de nuevo, éxito:

Información recibida en ESP8266 y RF, enviada a servidor MQTT

Información recibida en ESP8266 y RF, enviada a servidor MQTT

Sin embargo, esta vía tiene un problema: el receptor apenas es capaz de recibir la señal cuando se encuentra a unas pocas decenas de centímetros del emisor externo. Así que en la práctica ahora mismo es inusable. He probado con varios formatos de antena acoplados al módulo (173mm de largo, en hilo recto, en espiral…) con resultados bastante pobres. Tengo encargada en aliexpress una antena específica, pero aún tardará algunas semanas en llegar. Espero poder reportar mejoras una vez la reciba. :D

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , , , , , , , , , , , , ,

03 jul 19 Hacking lab sobre Modbus TCP. Introducción

Esta entrada es la parte 1 de 4 de la serie Hacking Lab Modbus TCP

Por temas relacionados con un máster de ciberseguridad industrial que estoy cursando he tenido que preparar una serie de ejercicios para el mismo, entre los que se encuentra la realización de un hacking lab. La idea de un hacking lab es preparar un entorno controlado en el que poder hacer ataques a un sistema para aprender posibles vulnerabilidades, técnicas para desvelarlas, y herramientas que se pueden utilizar para ello, a fin de ser capaz en un futuro de proteger un entorno real con las lecciones aprendidas en el entorno de pruebas.

Para la realización de este hacking lab opté por preparar un escenario en el que se pudiera realizar un ataque a un entorno de control industrial que hiciera uso de comunicaciones basadas en Modbus sobre TCP. Modbus es un protocolo de comunicación industrial desarrollado en 1979, y que constituye un estándar de facto en los sistemas de producción industrial. El objetivo general es perturbar el funcionamiento de un sistema de iluminación LED cuyo sistema de control está implementado empleando Modbus sobre TCP. El mismo consta de los siguientes elementos:

  • Una red plana que simula una red de control industrial. En este caso es una red del rango 192.168.0.0/24. Si bien en un caso real sería una red cableada, para este escenario de prueba es una red mixta cableada y WiFi, con un enrutador proporcionando conectividad a los distintos elementos de la misma.
  • Un PLC que actúa como Master Modbus, y que permite controlar, mediante el uso de tres bobinas (coils), el encendido y apagado de un sistema de iluminación LED de colores rojo, verde y azul. Este PLC, al no tener disponible ningún dispositivo real disponible, se simula mediante el aplicativo Node-RED de IBM con una librería Modbus desarrollada al efecto. Este PLC (virtual) tiene la IP 192.168.0.39, y escucha en el puerto 1502 (por razones de privilegios en el dispositivo, no se ha hecho uso del puerto estándar 502/TCP de Modbus).
  • Un actuador físico como Slave Modbus, que en base a las lecturas que realiza de los valores de las bobinas del Master Modbus, enciende y apaga los LEDs del sistema de iluminación. Este actuador físico se ha implementado con un dispositivo ESP8266 programado mediante Arduino IDE y librerías específicas. Las comunicaciones con el Master Modbus se realizan mediante protocolo Modbus sobre TCP. El actuador tiene la IP 192.168.0.34.
  • Un HMI de control de las luces, que permite controlar el encendido y apagado de las mismas mediante una aplicación web tipo SCADA. Este HMI se ha desarrollado mediante el aplicativo Node-RED de IBM y las librerías gráficas para desplegar cuadros de mando, así como una librería MODBUS desarrollada al efecto. EL HMI tiene la IP 192.168.0.31.
  • Un dispositivo atacante, que tiene como objeto descubrir sistemas Modbus en la red desplegada, e interferir los valores normales de operación de los mismos. Este dispositivo es una Raspberry Pi con Kali Linux instalado, teniendo la IP 192.168.0.99.

El siguiente diagrama de red muestra el sistema desarrollado:

Diagrama de la red

Diagrama de la red

En siguientes artículos iré dando mayor detalle de los dispositivos del entorno, así como de los pasos dados en el hacking lab, además de las conclusiones obtenidas de la puesta en marcha del mismo.

VN:F [1.9.20_1166]
Rating: 10.0/10 (1 vote cast)

Etiquetas: , , , , , , , ,

26 may 16 Comunicación serie con dispositivos ATtiny mediante TinyDebugSerial

Una de las dificultades a las que hay que enfrentarse a la hora de trabajar con dispositivos ATtiny (84/85, etc…) es la carencia de un dispositivo de comunicación serie, como se tiene con los Arduinos convencionales. Esto lleva a que sea difícil en ocasiones realizar tareas de diagnóstico de errores y resolución de problemas. Sin embargo, existe una (varias, en realidad) manera de comunicar mediante conexión serie con los ATtiny. La que yo he podido comprobar que funciona a la perfección es el uso de un adaptador USB a TTL.

Como requisitos previos para que esta solución funcione podemos distinguir los siguientes:

  • Utilización de los cores Arduino Tiny (http://code.google.com/p/arduino-tiny/)
  • Uso de un adaptador USB-TTL. En mi caso, estoy haciendo uso del adaptador SKU145351, que se puede encontrar a un precio muy reducido por Ebay. El mío monta el chip Silicon Labs CP2102.

Con estos componentes es posible hacer uso de comunicación TinyDebugSerial. Esta opción sólo permite la comunicación TX, es decir, el envío de información serie desde el Attiny al PC, pero para labores de resolución de errores es perfectamente válida.

Un ejemplo de comunicación básica sería el siguiente:

void setup() {
Serial.begin(9600);
}

void loop() {
Serial.println("Testing..");
}

Las conexiones con los ATtiny se realizarían haciendo uso de los siguientes puertos:

Attiny85: PIN PB3 (Pin físico 2)
Attiny84: PIN PB0 (Pin físico 2)
Attiny2313: PIN PD1

…además de los habituales puertos VCC y GND.

Conexión serie USB al ATiny

Conexión serie USB al ATiny

Nótese que no hay diferencias en el código con el que se cargaría en un Arduino convencional, y no se necesitan librerías añadidas. También es importante tener en cuenta que esta comunicación será válida para frecuencias de reloj de 8 MHz o inferiores.

Bibliografía:
Serial communication with the Tiny’s
Added TinyDebugSerial to attiny85

VN:F [1.9.20_1166]
Rating: 0.0/10 (0 votes cast)

Etiquetas: , , , , , ,

12 dic 15 Attiny85: módulo RF a 433 MHz, modo de bajo consumo, y cómo despertarlo con interrupciones

Hace ya bastante tiempo escribí algo acerca de un sistema de riego controlado por WhatsApp que estuve desarrollando. Se basaba en el uso de una Raspberry Pi que actuaba como cerebro del sistema de riego y de comunicaciones, permitiendo el control de todo el sistema mediante mensajería por WhatsApp. La Raspberry, a su vez, se comunicaba con los los relojes de riego mediante módulos de radiofrecuencia a 433 MHz, un sistema de comunicación barato y razonablemente efectivo. En el otro lado, como se comentó en su momento, la válvula de riego se controlaba con un chip Attiny85, programado mediante Arduino.

Como se vio en su momento, el sistema funcionaba razonablemente bien. Sin embargo, varios problemas me llevaron a un callejón sin salida. El principal de ellos, y del que hablaremos hoy, era el consumo del receptor Attiny85. Sobre el papel es un sistema de muy bajo consumo, óptimo para este tipo de funciones. Sin embargo, el sistema de control de la válvula de riego no dejaba demasiado espacio para una batería, así que la alimentación disponible era, como poco, reducida. Pronto se demostró el que el Attiny con el sistema de radiofrecuenca devoraba la batería. Ésta apenas duraba unas 48-72 horas. Y esto, en un sistema que se supone que ha de ser autónomo y con un bajo mantenimiento, era sencillamente inaceptable, sobre todo si lo comparamos con relojes de riego de jardón convencionales, que con un par de pilas AA o una pila cuadrada de 9v pueden funcionar de manera ininterrupida durante meses.

Probé varias soluciones, desde el uso inicial de una batería recargable de 9v hasta el uso de un panel solar con una batería de móvil incorporada. Éste último caso consiguió producir mejoras, llegando el sistema a funcionar durante una semana de manera ininterrumpida. Pero en cualquier caso, no era una gran mejora. Tocaba afrontar el problema de base: un exceso de consumo.

Batería cuadrada de 9v y panel solar con regulador

Batería cuadrada de 9v y panel solar con regulador

En efecto, el problema estaba provocado por un exceso de consumo. Tal y como estaba diseñado, el sistema estaba permanentemente a la escucha de señales por RF, en un bucle sin fin, dado que la señal de encender o apagar la válvula de riego podía darse en cualquier momento. Esta aproximación era, como poco, inadecuada desde el punto de vista del consumo.

Para mejorar esto, probé varias alternativas: desde emitir sólo en determinadas ventanas de tiempo, hasta desconectar la alimentación al módulo de radiofrencuencia y activarlo sólo durante varios segundos cada minuto. Opciones bastante malas, la verdad, ya que se basaban en la precisión de un reloj interno que, como es conocido, no es un prodigio de la precisión.

Otra posibilidad hubiera podido ser un método en el que el Attiny consultara a la Raspberry si había algún comando por ejecutar. Pero por desgracia, los módulos RF de 433 MHz son unidireccionales, por lo que hubiera sido preciso incorporar un emisor al Attiny y un receptor a la Raspberry, complicando de manera innecesaria todo el sistema. Finalmente, la solución vino de mano de dos elementos presentes en el Attiny. El modo sleep y el uso de interrupciones.

El Attiny85 dispone de varios modos de bajo consumo (sleep mode) que sirven para reducir el consumo del chip cuando está a la espera de algún evento. En el caso del Attiny85, puede reducir el consumo hasta en un 90%. Pero no se trataba sólo de dormir al chip, sino de ser capaz de despertarlo cuando se recibiera una recepción de datos en el módulo de RF. Y para ello, nos encontramos con las interrupciones.

Las interrupciones son eventos que provocan un cambio en el estado de reposo o ejecución de un programa -en este caso, un programa cargado en el Attiny85-. Hay interrupciones tanto hardware como software, siendo las hardware las provocadas por un evento externo al programa en sí. Dentro de las interrupciones hardware, en el caso de Arduino, podemos distinguir las interrupciones Externas, y las provocadas por un Cambio en el Pin. El nombre es un poco confuso, pues ambas son externas al chip en sí, pero mientras las Externas están limitadas a un número concreto de patillas en el chip, las de Cambio en Pin pueden ocurrir en cualquiera de las patillas. En el caso concreto del Attiny85, las Externas sólo se producen en el Pin2 (INT0, patilla 7), mientras que las de Cambio en Chip se pueden producir en cualquier otra patilla.

De hecho, es factible despertar al Attiny85 del modo de bajo consumo mediante el uso de interrupciones. En el caso concreto del artículo enlazado, se usa el Pin3 (patilla 7) -luego se usa el modo de Cambio de Pin- para despertar al chip del modo de bajo consumo, como he podido comprobar personalmente (el ejemplo se basa en el uso de un botón conectado a 5v). Sin embargo, a la hora de probarlo con el módulo de RF a 433 MHz el sistema no funcionaba. No era capaz de realizar cambios en el sistema.

A modo de recordatorio, el sistema de control de la válvula consiste básicamente en un relé que activa o desactiva la válvula en función del tiempo que se desea mantener activo el riego. Este relé está controlado por una de las patillas del Attiny, protegida mediante un optoacoplador.

Tras varias pruebas, pude averiguar que el problema estaba causado por una particularidad en el receptor del módulo RF. Sólo he sido capaz de hacerlo comunicar con el chip Attiny a través del del pin de Interrupción Externa (Pin2, INT0), por lo que el ejemplo referenciado anteriormente no resultaba válido. En mi caso, ha sido necesario hacer uso de la patilla INT0:

#include
#include
#include

RCSwitch mySwitch = RCSwitch();
const int rele = 4;
const int dataPin = 0; //INT0, PCINT2
void setup() {
pinMode(dataPin, INPUT);
digitalWrite(dataPin, HIGH);
pinMode(rele, INPUT);
mySwitch.enableReceive(dataPin);

// Flash quick sequence so we know setup has started
for (int k = 0; k < 10; k = k + 1) {
if (k % 2 == 0) {
pinMode(rele, OUTPUT);
}
else {
pinMode(rele, INPUT);
}
delay(250);
} // for
}

void sleep() {

GIMSK |= _BV(PCIE); // Enable Pin Change Interrupts
PCMSK |= _BV(PCINT2); // Use PB3 as interrupt pin
ADCSRA &= ~_BV(ADEN); // ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // replaces above statement

sleep_enable(); // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
sei(); // Enable interrupts
sleep_cpu(); // sleep

cli(); // Disable interrupts
PCMSK &= ~_BV(PCINT2); // Turn off PB2 as interrupt pin
sleep_disable(); // Clear SE bit
ADCSRA |= _BV(ADEN); // ADC on

sei(); // Enable interrupts
} // sleep

ISR(PCINT0_vect) {
// This is called when the interrupt occurs, but I don't need to do anything in it
}

void loop() {

if (mySwitch.available()) {

sleep();
int value = mySwitch.getReceivedValue();

if (value == 0) {
// Serial.print("Unknown encoding");
} else {

pinMode(rele,OUTPUT);
delay(10000);
pinMode(rele,INPUT);
}
mySwitch.resetAvailable();
}
}

(Explicación rápida del ejemplo: Se declaran INT0 como receptor de RF, y el Pin4 como control del relé. Se realiza un ciclo de encendido y apagado del relé al inicio para mostrar que el programa ha iniciado, se declara la interrupción del modo de bajo consumo con INT0, y se pasa al bucle principal. Se espera a una interrupción, se comprueba que la señal RF recibida es correcta, y se enciende el relé durante 10 segundos)

Resultado: ¡éxito! No sólo el sistema funciona, sino que he podido comprobar una gran mejora en el consumo del sistema. Durante la fase activa del programa, en la que el relé está activo y se ha recibido la señal de radiofrecuencia, todo el sistema consume unos 9 mA. Cuando está en modo de bajo consumo, a la espera de recibir la señal, baja a niveles inferiores a 1 mA.

VN:F [1.9.20_1166]
Rating: 9.0/10 (2 votes cast)

Etiquetas: , , , ,

21 sep 14 Solución a la lentitud del IDE Arduino en Windows 7

Desde hace algunas semanas vengo notando una exasperante lentitud a la hora de hacer uso del IDE de Arduino en Windows 7. El tiempo de carga inicial es exagerado, pero aún lo es más el uso del menú de Herramientas (Tools). Y todo ello especialmente si lo comparamos con la respuesta del IDE en Debian, en una máquina mucho más limitada.

Por suerte, tirando del hilo he podido encontrar este artículo: Slow Arduino IDE, en el que explican que la causa del problema reside en una librerñia para comunicarse con los puertos de comunicación (rxtx), que al ser el IDE es un proyecto de plataforma cruzada, da algunos problemas en Windows, tanto Vista, como 7 en adelante.

¿La solución? Reemplazar la dichosa librería por una optimizada para Windows. Y aunque el artículo es antiguo, el mismo autor ha realizado una actualización este verano, indicando que la solución sigue siendo válida.

VN:F [1.9.20_1166]
Rating: 0.0/10 (0 votes cast)

Etiquetas: , ,