ThingJS v1.0-alpha


Durante los últimos dos años he estado desarrollando mi propia plataforma IoT y hoy estoy listo para mostrar su versión alfa.


Junto con un socio, creamos y admitimos dispositivos IoT. Desmantelamos más de un cobertizo de rastrillo en el proceso de esta actividad. ThingJS nació no tanto por el deseo como por la necesidad de hacernos la vida más fácil, sino al mismo tiempo, espero, para ti.


El artículo será interesante para las personas que están cerca del tema de IoT y que ya han hecho algo en esta área. Un punto importante será que la plataforma debería interesar (de repente) a los desarrolladores de JavaScript, ya que Este lenguaje se elige como la base de la plataforma. Por supuesto, los desarrolladores de C / C ++ también tendrán algo para leer.


Primero, hablaré sobre los problemas clave que encontramos al desarrollar dispositivos IoT, luego describiré cómo la plataforma los maneja y, al final, todo es aburrido: el video , la parte técnica y puedes tocar todo en vivo .



Problemas de IoT:


- El problema de los brazos cortos.


IoT se basa en un ecosistema. El desarrollo de su concepto y arquitectura técnica es realmente mucho trabajo. Además, aún necesita desarrollar un montón de firmware para dispositivos heterogéneos. Para inventar e implementar el transporte para el intercambio de datos entre dispositivos en varios principios físicos y lógicos. Expande los recursos en la nube. Trabajar interfaces de usuario. Etc. etc.


Incluso si un especialista individual tiene las habilidades necesarias para hacer esto, entonces simplemente no tiene suficiente tiempo (manos) para implementar tal idea. Si bien él lo cortará, ella se volverá obsoleta.


- El problema de la torre de Babel


El desarrollo de un ecosistema de IoT completo requiere una pila tecnológica muy amplia. Ser una pila completa en IoT es sencillo ... difícil. Necesito experiencia en todas partes. No todos pueden presumir de una gama tan amplia de conocimientos e incluso de experiencia. Y aquí la pregunta no está en las habilidades mentales. Esta es una conclusión obvia del problema de la mano corta.


Crear un ecosistema verdaderamente rico requiere el trabajo de muchos especialistas bastante limitados, pero con un profundo conocimiento en su campo. Estos especialistas hablan diferentes idiomas, usan diferentes patrones y, a menudo, entienden los términos elementales de diferentes maneras. Y dado que IoT se basa en dispositivos con recursos limitados, las comunicaciones efectivas son críticas para la realización de lo que se pretende.


- El problema del síndrome de Estocolmo


Hoy hay vendedores que desarrollan sus ecosistemas. Estos son Google, Microsoft, Yandex, Megáfono, MTS, etc. Algunos de ellos le permiten integrar sus propias cosas en sus ecosistemas en sus términos. Esto cubre en gran medida los problemas descritos anteriormente. Pero crea uno nuevo: la adicción. Y a los vendedores les gusta cambiar las condiciones para la integración. Y aún más, no hay cuestión de autorrealización en este paradigma.


Soluciones a problemas:


- Comunidad, adicción, moda, juventud.


Los problemas descritos anteriormente, de hecho, bloquean el acceso al desarrollo de IoT para individuos. El desarrollo de la plataforma se lanzó con la conciencia de estos problemas. Se sentaron las bases para el desarrollo de la plataforma a través de la comunidad.


Para implementar esta idea, la plataforma, por supuesto, viene con una base de código abierto, y también tiene un paradigma de dependencia en todas las capas.


Si no sabe qué son las adicciones, es hora de conocerlas. Pero si intentas explicarlo de manera muy simple, entonces el módulo que estás desarrollando puede depender de otro que escriba tu amigo. Y accederá a su módulo a través de una interfaz predefinida.


Por lo tanto, al mismo tiempo, de manera independiente, muchas personas pueden desarrollar sus propios componentes de plataforma y reutilizar los existentes desarrollados por alguien. Esto resuelve fundamentalmente el problema de las manos cortas.



Además, el problema de la "Torre de Babel" se está resolviendo. Las dependencias se crean de modo que los distintos niveles de la plataforma, desarrollados en diferentes idiomas, tengan un mecanismo predeterminado para construir dependencias entre ellos.


Por ejemplo, un desarrollador de C puede aprovechar un componente de front-end listo para usar al proporcionarle la interfaz requerida. O, por el contrario, el desarrollador front-end puede usar un componente listo para usar escrito en C. Es decir todos harán lo que mejor sabe.


- Más promesas y abstracciones.


El protocolo de comunicación entre dispositivos no está definido. En cambio, hay una abstracción: un bus de datos. El dispositivo puede enviar un evento al bus o escuchar el bus. No está claro quién escribe en el autobús y quién recibe, por adelantado. Y cuando también. El intercambio de datos asíncrono y la entrega no están garantizados. En general, el infierno. Sin pánico Así concebido.


La cuestión es que el ecosistema es un grupo de dispositivos independientes y autosuficientes. En cualquier momento, algunos dispositivos pueden no estar disponibles. Por varias razones Para detener la actividad de otros dispositivos si una parte no está disponible, no es el mejor escenario. Es necesario legalizar lo que no se puede evitar.


La plataforma implementa el paradigma de las promesas de proporcionar eventos. El primer dispositivo se suscribe a la promesa del segundo de darle información. Pero no hay garantías. El suscriptor debe decidir qué hacer en caso de que le proporcione datos de manera prematura.


El problema de la comunicación sincrónica se resuelve transmitiendo eventos a través del bus con enlaces a canales sincrónicos. El protocolo de canal síncrono está determinado por el tipo de evento en sí. Por ejemplo, puede enviar un evento con el tipo "do-render-video-stream" y cómo enviar cámaras IP WEB como carga útil. Por lo tanto, el destinatario sabrá que necesita reproducir la transmisión de video desde la dirección especificada.



Pero, ¿cómo funciona físicamente el autobús? La implementación del autobús recae en la comunidad. El neumático se expande con el transporte que requiere su proyecto. Por ejemplo, se recibe un evento a través de http y se retransmite a través de UART. Para todos los elementos del ecosistema, exteriormente nada cambiará.


- Dispositivos virtuales de IoT


Para ThingJS, una cosa no es solo una cosa física, sino también una aplicación especial, una cosa virtual. Además, una cosa física puede contener varias cosas virtuales (aplicaciones) que usan los recursos de una cosa física.


Este enfoque le permite unificar la interacción entre el backend condicional (controlador / servidor / nube, etc.) y el frontend (navegador, aplicación, etc.), así como b2b e incluso f2f. Construya una matriz, no una jerarquía de interacciones.



Un ejemplo simple sería una cámara WEB, que en sí misma tiene una cosa virtual: una interfaz de usuario. Cuando el usuario va a la dirección http://192.168.4.1 , se abre la página WEB, donde lo virtual comienza a "vivir". La cámara (cosa física) y la página (cosa virtual) se convierten automáticamente en un ecosistema donde está disponible un bus de datos unificado. A través de él, lo virtual se comunica con lo físico. En este caso: lo físico le dice a lo virtual a través del bus la dirección del flujo de video, su estado, etc., y lo virtual le muestra al usuario el video y le da los comandos necesarios a lo físico.


La continuación lógica es la capacidad de alojar cosas virtuales en las nubes e incluirlas en un ecosistema común. Y esto, a su vez, le permite crear dispositivos virtuales con enormes recursos que resuelven problemas, por ejemplo, disponibles para IA.


Puede crear dichos dispositivos usted mismo o usar los ya creados. El síndrome de Estocolmo está derrotado. Usted mismo determina de qué depende su proyecto y cómo lo desarrollará.


Informacion tecnica


Estructura de aplicación de ThingJS



Pila de tecnología


La plataforma de hardware seleccionada es el controlador ESP32 . La plataforma fue diseñada como hardware independiente. Pero, desafortunadamente, no hubo tiempo para particionar en otros dispositivos.


Para el desarrollo del firmware, se utilizan las herramientas recomendadas de Espressif . El firmware está desarrollado en C. El colector cmake. El proyecto utiliza el concepto de componente, también promovido por Espressif.


Además de esp-idf, se utiliza Mongoose WEB Server , así como un intérprete de JavaScript modificado Mongoose mJS .


Para el desarrollo de aplicaciones, JavaScript se usa con el marco VUE 2. Cree aplicaciones usando webpack. El administrador de paquetes es npm. El VUE CLI se utilizó como base para el entorno de desarrollo.


Para estandarizar la visualización de aplicaciones y aliviar los dolores de la creatividad de la interfaz de usuario, el paquete vuetifyjs está incluido en la plataforma.


Características del entorno de desarrollo


Para desarrolladores de JavaScript (cosas virtuales):


  • IDE recomendado - WEBStorm;
  • Todos los beneficios que otorga VUE CLI e IDE;
  • Depuración de aplicaciones dentro del sistema (depurador mJS en el controlador);
  • MJS implementa el comando depurador, que le permite llamar al depurador en un lugar arbitrario;
  • Carga en caliente de archivos actualizados al controlador durante el desarrollo (los desarrolladores de JavaScript ya no pueden vivir sin esta función);
  • El desarrollo en tiempo de ejecución se combina con un controlador real. Usted programa y, allí mismo, ve el resultado en el hardware;
  • Configurado ESLint para comprender los objetos de la plataforma.

Para desarrolladores de C (cosas físicas):


  • IDE recomendado - CLion;
  • Todas las ganancias esp-idf e IDE;
  • La plataforma se divide en componentes como parte del concepto esp-idf;
  • Fácil integración con la plataforma de componentes nativos.

Dispositivos compatibles


Solo ESP32 es compatible actualmente. El chip es popular debido a su disponibilidad con sorprendentes características técnicas. En base a esto, se han creado muchos dispositivos IoT listos para usar que se pueden usar con ThingJS.


Comparación con la competencia.


Sugiero no correr tan lejos. No me atrevo a llamar competidores a las plataformas comerciales. Y el código abierto aparece y desaparece sin dejar un rastro notable. Por lo tanto, no hice una comparación. Sin embargo, si alguien tiene un deseo, estoy listo para publicar el resultado de su trabajo aquí.


Inicio rápido


Solo tengo que mirar



Quiero intentar


Para probar la plataforma en hardware real, necesitará cualquier dispositivo basado en ESP32 con flash 4mb y la capacidad de flashearlo a través de USB. Pero la placa base ESP32 v2 es la más adecuada.



Puede comprar tales cosas sin problemas en Aliexpress o Ebay. Además, incluso hay oficinas de representación en Rusia. Yo personalmente compro en San Petersburgo .


Para probar el funcionamiento de la aplicación de prueba "Parpadeo", debe conectar un LED. Algunas versiones de las placas tienen un LED preinstalado conectado a GPIO2. Si tiene un tablero así, entonces no puede hacer nada. El parpadeo debería funcionar sin movimientos innecesarios. Si solo tiene un diodo (fuente de alimentación), deberá conectar el diodo indicador usted mismo. Esto no es nada complicado.


Necesitará cualquier indicador LED y resistencia de 1 a 5K.



Lo único que queda es implementar el paquete de usuario en el dispositivo. Puedes llevarlo aquí . Las instrucciones de implementación se encuentran allí.




Blink es un ecosistema simple que consta de un dispositivo virtual que implementa la interfaz de usuario y uno físico. Un dispositivo virtual comienza desde un dispositivo físico cuando se accede a él a través de un navegador.


El guión es simple. Al instalar la aplicación en un dispositivo físico, el LED (previamente conectado a él) comienza a parpadear a una frecuencia de 1 Hz. El usuario puede encender o apagar el parpadeo del diodo desde la interfaz. Puedes ver el video en la sección "Solo puedo ver".


Las fuentes están en el repositorio src / aplicaciones / blink. Para recopilar blink y jugar con él, solo necesita este repositorio. Asegúrese de que ya tiene instalados git, npm y nodejs.


git clone --branch alpha https://github.com/rpiontik/ThingJS-front cd ThingJS-front npm install npm run build 

Si todo salió bien, terminarás con algo como lo siguiente:



Felicidades Has creado tu primera aplicación ThingJS. Puede encontrarlo en la carpeta dist / apps / blink e inmediatamente intente instalarlo en el dispositivo, guiado por el video de la sección "Solo puedo ver" .



ArchivoDescripción
scripts / blink.jsEl script que está instalado en el controlador.
blink.jsPunto de montaje del componente de aplicación
Blink.vueComponente VUE que implementa la interfaz de usuario
favicon.svgIcono de la aplicación
langs.jsPaquete de idioma de la aplicación
manifest.jsonManifiesto de solicitud

Puede familiarizarse con todos los detalles de la aplicación usted mismo. Me enfocaré en varios archivos.



 { "name": "Blink", "vendor" : "rpiontik", "version" : 1, "subversion" : 0, "patch" : 0, "description": { "ru": " ", "en": "Blink Example" }, "components": {...}, "scripts": {...}, "requires" : {...} } 

Como lo indica el nombre del archivo, este es el manifiesto de la aplicación. Tiene metadatos generales sobre el propósito de los cuales es fácil de adivinar. Además de ellos, hay tres bloques importantes. Miremos de cerca:



 "components": { "blink-app": { "source": "blink.js", "intent_filter": [ { "action": "thingjs.intent.action.MAIN", "category": "thingjs.intent.category.LAUNCH" } ] } } 

El bloque describe toda la base de componentes de la aplicación. El campo "fuente" apunta al punto de montaje del componente (consulte blink.js) y es el punto de entrada del ensamblaje para webpack ( entrada ). Por lo tanto, cada componente se emitirá en un paquete separado. Este paquete se cargará según sea necesario ( carga diferida ).


Una estructura importante es intent_filter . Si programa para Android, encontrará algo familiar para usted. Y no te equivoques. El sistema genera eventos de interfaz y servicio a los que se suscribe el componente. Si se produce un evento que satisfaga las condiciones de filtrado, el componente se cargará y el control se transferirá al punto de montaje.


En este caso, el componente "aplicación de parpadeo" está suscrito al evento de inicio del componente de interfaz principal de la aplicación. Cuando el iniciador inicie la aplicación, se introducirá este componente.


Si modifica el manifiesto cambiando la línea


thingjs.intent.category.LAUNCH >> thingjs.intent.category.PREFERENCE


, luego de su ensamblaje e instalación resulta que la aplicación ha dejado de abrirse en el escritorio. Pero apareció un nuevo "mosaico" en la sección "Configuración". Al mismo tiempo, nada ha cambiado funcionalmente.


Por lo tanto, le indicamos al lanzador que este componente es un elemento de interfaz para personalizar nuestra aplicación. Y este componente comenzó a aparecer en la configuración.



 "scripts": { "entry": "blink", "subscriptions" : ["$-script-restart", "blink"], "modules": { "blink": { "hot_reload": true, "source": "scripts/blink.js", "optimize": false } } } 

Este bloque es similar en función al bloque de "componentes", pero describe la base del componente de la aplicación en el lado del controlador.


Indica claramente el punto de entrada. En el campo "entrada". Por separado, prestaré atención a que al instalar la aplicación, el script no se inicia inmediatamente. Se inicia solo cuando ocurre uno de los eventos a los que está suscrito el script.


El campo "suscripciones" es responsable de las suscripciones. Ahora indica dos eventos:


  • $ -script-restart : ocurre cuando el sistema se inicia o reinicia;
  • blink es un evento personalizado que es relevante para el ecosistema blink.

En el bloque "módulos", sigue la descripción de los scripts. Notaré dos campos:


  • hot_reload : si este campo se establece en verdadero, cuando se cambia un archivo en modo de desarrollo, se descargará automáticamente al controlador (recarga en caliente);
  • optimizar : si es verdadero, al compilar el proyecto, el script se optimizará y agregará.


 "requires" : { "interfaces" : { "blink" : { "type" : "bit_port", "required" : true, "default" : 2, "description" : { "ru" : "LED ", "en" : "LED indicator" } } } } 

Probablemente ya haya notado que al instalar la aplicación, debe seleccionar el pin en el que parpadeará el LED. Sin embargo, por defecto ya está seleccionado como GPIO2. Este bloque es responsable de esta configuración.


En este bloque se indican las dependencias. En este caso, para que la aplicación funcione, debe proporcionar una interfaz con el tipo "bit_port". Esta interfaz es un requisito obligatorio (obligatorio = verdadero) y, de forma predeterminada, se especifica GPIO2 (predeterminado = 2). Se proyectará en el script con el nombre "parpadeo".


Al instalar la aplicación, se tiene en cuenta el perfil del equipo en el que se implementarán los scripts. Este perfil enumera las interfaces disponibles y los recursos de hardware disponibles para ellas (en particular, pines y sus combinaciones). Comprueba la compatibilidad de requisitos y equipos. Si el equipo puede satisfacer los requisitos de la aplicación, se muestra al usuario un esquema de asignación de recursos, donde los recursos primarios se asignan automáticamente, teniendo en cuenta las recomendaciones del manifiesto. Es decir desde ese mismo campo "predeterminado".


Por lo tanto, se pueden instalar varias aplicaciones en un dispositivo, que pueden compartir recursos de hardware entre ellos.



 import App from './Blink.vue'; import Langs from './langs'; $includeLang(Langs); $exportComponent('blink-app', App); 

El archivo es el punto de montaje del componente anunciado en el manifiesto (ver manifest.js / components). Registra el VUE del componente 'blink-app' a través del método de abstracción $ exportComponent, y también registra el paquete de idioma.


Usted puede preguntar: ¿por qué tantas dificultades? ¿Por qué no registrar inmediatamente el componente VUE que especifique en la fuente? El hecho es que el manifiesto describe componentes públicos. Estos componentes pueden ser solicitados por aplicaciones de terceros (dependencias de tiempo de ejecución). El punto de montaje, a su vez, puede registrar componentes relacionados (para uso interno), así como servicios. Es decir, preparar el entorno del componente.



 export default { name: 'Blink', watch: { blink_state (state) { // Send event to script this.$bus.$emit($consts.EVENTS.UBUS_MESSAGE, 'blink', state); } }, data () { return { blink_state: true }; } }; 

El código habla por sí mismo. Cuando se cambia la propiedad "blink_state", se envía un mensaje al bus ($ bus) con el valor actual. Esto es todo lo que necesita hacer para que el script en el lado del controlador reciba el comando deseado.



 let active = true; let state = true; // Set port direction $res.blink.direction($res.blink.DIR_MODE_DEF_OUTPUT); // Run background process setInterval(function () { if (active) { // $res - is container with required resources $res.blink.set(state); // Do invert state = !state; } }, 1000); // Event listener // $bus - system bus interface $bus.on(function (event, content, data) { if (event === 'blink') { active = !!JSON.parse(content); } }, null); 

En general, el código es muy similar al uso clásico de un temporizador en JavaScript. Excepto que no está en este dialecto de JavaScript. Se implementa en la plataforma. Conoce a este mJS . Puede obtener más información al respecto en la página oficial del proyecto.


Para las necesidades de la plataforma, se finaliza el dialecto. Se han introducido temporizadores, así como un comando tan útil como "depurador". Bueno, el depurador en sí. Más información sobre esto por separado en la sección "Entorno de desarrollo" .


Presta atención a los objetos globales de la plataforma. Se nombran con el carácter "$".


  • $ res : contiene recursos que se asignan al script;
  • $ bus - interfaz de bus .

Porque la aplicación solicitó una interfaz con el tipo "bit_port" (ver profile.json / require) y el nombre "blink", se le asignó como $ res.blink. La interfaz implementa solo tres funciones:


  • set (value) : establece el nivel GPIO
  • get () - obtiene el nivel GPIO actual
  • direction (value) : establece el modo GPIO

Para la función de dirección, las constantes disponibles se describen a través de la misma interfaz $ res.blink.: DIR_MODE_DISABLE; DIR_MODE_DEF_INPUT; DIR_MODE_DEF_OUTPUT; DIR_MODE_INPUT_OUTPUT_OD; DIR_MODE_INPUT_OUTPUT.


La suscripción a eventos de bus se realiza a través del método $ bus.on. En este caso, todos los eventos a los que está suscrito el script pasarán al controlador. El controlador acepta tres parámetros:


  • evento : identificador de evento . En este caso, solo dos son posibles: "$ -script-restart" y "parpadear". De los cuales solo se procesa uno: parpadeo. La suscripción a la segunda es necesaria solo para que el script se inicie inmediatamente al iniciar el sistema.
  • contenido : los datos pueden venir con el evento. Su tamaño está limitado a 126 bytes, teniendo en cuenta la longitud del identificador de evento.
  • datos : datos que se transmiten al suscribirse al evento como un segundo parámetro. Y en este caso, son nulos.

Las interfaces son extensibles. A continuación encontrará una descripción de cómo crear su propia interfaz.


Implementación de interfaz


ThingJS le permite expandir los recursos de hardware y servicio disponibles a través de interfaces especiales. Puede crear de forma independiente una interfaz que implementará cualquier complejo, preciso, cargado, etc. funcional


Por ejemplo, puede implementar una interfaz de integración con su servicio en la nube. O un proceso asíncrono en segundo plano con el que el script podrá intercambiar mensajes. Bueno, o implementar soporte de pantalla. Será igualmente fácil de hacer y usar. Tanto tú como los demás. Es cierto, para esto necesitas saber C.


Considere la implementación de la interfaz bit_port, que se usa en el ejemplo de Blink. Para comenzar, debe implementar el proyecto de lanzamiento alfa ThingJS-template . La documentación de implementación está en el proyecto mismo.


 git clone --branch alpha https://github.com/rpiontik/ThingJS-template 

El proyecto incluye componentes:


  • ThingJS-boards - contiene configuraciones de dispositivos. Hasta ahora, solo ESP32_CORE_BOARD V2 y compatible;
  • ThingJS-extern : bibliotecas de proyectos de terceros que utiliza ThingJS;
  • ThingJS-core - núcleo de la plataforma;
  • ThingJS-front - entorno de desarrollo de aplicaciones;
  • ThingJS-stdi - interfaces estándar.

Estamos interesados ​​en el proyecto ThingJS-stdi. Su estructura es la siguiente:


ArchivoDescripción
implementación / tgsi_bit_port.cImplementación de la interfaz Bit_port
implementación / tgsi_bit_port.hArchivo de encabezado de interfaz Bit_pro
CMakeLists.txtcmake build script
README.md
sdti_utils.hAyudantes
thingjs_stdi.cPunto de montaje de interfaz
thingjs_stdi.hArchivo de encabezado de punto de montaje

De hecho, solo estamos interesados ​​en un archivo: implementación / tgsi_bit_port.c. Contiene todo lo que requiere una explicación por separado.


 void thingjsBitPortRegister(void) { static int thingjs_bit_port_cases[] = DEF_CASES( DEF_CASE(GPIO0), DEF_CASE(GPIO2), DEF_CASE(GPIO3), DEF_CASE(GPIO4), DEF_CASE(GPIO5), DEF_CASE(GPIO12), DEF_CASE(GPIO13), DEF_CASE(GPIO14), DEF_CASE(GPIO15), DEF_CASE(GPIO16), DEF_CASE(GPIO17), DEF_CASE(GPIO18), DEF_CASE(GPIO19), DEF_CASE(GPIO21), DEF_CASE(GPIO22), DEF_CASE(GPIO23), DEF_CASE(GPIO25), DEF_CASE(GPIO26), DEF_CASE(GPIO27), DEF_CASE(GPIO32), DEF_CASE(GPIO33) ); static const struct st_thingjs_interface_manifest interface = { .type = "bit_port", .constructor = thingjsBitPortConstructor, .cases = thingjs_bit_port_cases }; thingjsRegisterInterface(&interface); } 

La función thingjsBitPortRegister registra un componente en el núcleo ThingJS. Para hacer esto, llama a la función thingjsRegisterInterface, a la que pasa una estructura con una descripción de interfaz.


  • tipo : identificador de interfaz. Es él quien se especifica como el tipo en el archivo manifest.json de la aplicación;
  • constructor : enlace al constructor de la interfaz. Se llama a la función cada vez que necesita crear una nueva instancia de la interfaz;
  • cases es una matriz que describe los posibles recursos de hardware que la interfaz puede usar para su trabajo. En este caso, estos son GPIO individuales. Pero sus combinaciones o dependencias pueden describirse por separado.

El constructor de la interfaz monta la interfaz en la máquina mJS.


 mjs_val_t thingjsBitPortConstructor(struct mjs *mjs, cJSON *params) { //Validate preset params //The params must have pin number if (!cJSON_IsNumber(params)) return MJS_UNDEFINED; //Get pin number gpio_num_t gpio = params->valueint; //Create mjs object mjs_val_t interface = mjs_mk_object(mjs); /* Configure the IOMUX register for pad BLINK_GPIO (some pads are muxed to GPIO on reset already, but some default to other functions and need to be switched to GPIO. Consult the Technical Reference for a list of pads and their default functions.) */ gpio_pad_select_gpio(gpio); //Add protected property to interface mjs_set(mjs, interface, "gpio", ~0, mjs_mk_number(mjs, gpio)); //Set protected flag mjs_set_protected(mjs, interface, "gpio", ~0, true); //Bind functions mjs_set(mjs, interface, "set", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) thingjsBitPortSet)); mjs_set(mjs, interface, "get", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) thingjsBitPortGet)); mjs_set(mjs, interface, "direction", ~0, mjs_mk_foreign_func(mjs, (mjs_func_ptr_t) thingjsBitPortDirection)); //Consts mjs_set(mjs, interface, "DIR_MODE_DISABLE", ~0, mjs_mk_number(mjs, GPIO_MODE_DISABLE)); mjs_set(mjs, interface, "DIR_MODE_DEF_INPUT", ~0, mjs_mk_number(mjs, GPIO_MODE_DEF_INPUT)); mjs_set(mjs, interface, "DIR_MODE_DEF_OUTPUT", ~0, mjs_mk_number(mjs, GPIO_MODE_DEF_OUTPUT)); mjs_set(mjs, interface, "DIR_MODE_INPUT_OUTPUT_OD", ~0, mjs_mk_number(mjs, GPIO_MODE_INPUT_OUTPUT_OD)); mjs_set(mjs, interface, "DIR_MODE_INPUT_OUTPUT", ~0, mjs_mk_number(mjs, GPIO_MODE_INPUT_OUTPUT)); //Return mJS interface object return interface; } 

Cómo se pasan los parámetros:


  • mjs : contexto de ejecución global;
  • params : parámetros de inicialización de la interfaz. En este caso, este es el número GPIO.

Se crea un objeto de "interfaz" mJS, donde se montan los métodos y propiedades de la interfaz:


  • gpio : propiedad de solo lectura en la que se almacena el número de GPIO utilizados;
  • set - método para configurar el nivel de señal;
  • get : un método para obtener el nivel de señal actual;
  • dirección : configuración del modo GPIO;

Además, se montan constantes con las que pueden operar los scripts (DIR_MODE_DISABLE, DIR_MODE_DEF_INPUT, etc.).


Después de crear la interfaz, se monta bajo un identificador específico (en el ejemplo de Blink es "blink") en el objeto global $ res. Se puede encontrar un ejemplo de uso en la sección Blink ( scripts / blink.js ).


Puede formatear interfaces en componentes o paquetes separados. Esto te permitirá ensamblar el firmware como lego.


Entorno de desarrollo


Desarrollo de aplicaciones


El entorno de desarrollo de aplicaciones se basa en VUE CLI, que se ha perfeccionado para satisfacer las necesidades de la plataforma ThingJS. Este es un tenedor duro, incl. Vale la pena esperar las nuevas funciones de VUE CLI si facilitan directamente la vida.


Para implementar el entorno, debe clonar el proyecto de lanzamiento alfa ThingJS-front . Asegúrese de que ya tiene instalados git, npm y nodejs.


 git clone --branch alpha https://github.com/rpiontik/ThingJS-front cd ThingJS-front npm install 

Al desarrollar, recomiendo usar la IDE WEBStorm.


La composición y estructura del proyecto se hereda de VUE CLI. Reflejaré diferencias significativas:


  1. Se modificaron los scripts de compilación en la carpeta de compilación.
  2. Se ha agregado una variable de entorno "HW_DEVICE_URL" a la configuración del entorno de desarrollo (config / dev.env.js). Es necesario especificar un enlace al dispositivo físico con el que trabajará.
  3. Ha aparecido la carpeta del sistema src / aplicaciones. Contiene aplicaciones que se construirán automáticamente. En particular, contiene dos aplicaciones: ante (lanzador) y blink (aplicación).
  4. Todo lo que está encima de la carpeta src / aplicaciones se considera módulos y recursos de la plataforma. Por supuesto, puede hacer cambios en ellos, pero en este caso, aparecerán en el controlador solo después de flashearlo. T.ch. A menos que establezca objetivos específicamente para usted, es mejor no tocarlos.

Para las pruebas, puede iniciar inmediatamente el servidor de desarrollo. Aunque no puede desarrollarse completamente sin el hardware físico, esto no interfiere con el desarrollo de la interfaz. Y así, el servidor de desarrollo comienza:


 npm run dev 

El resultado debería ser algo como esto:



Al abrir el navegador e ingresar http://0.0.0.0:8080 en la barra de direcciones, verá la plataforma en modo de desarrollo:



El proceso de desarrollo de la interfaz en sí no es muy diferente del clásico desarrollo front-end en VUE. Excepto que hay objetos de plataforma global que debe tener en cuenta:


  • $ const - contiene constantes de plataforma, así como paquetes de idiomas;
  • $ bus - bus de datos;
  • $ store - almacenamiento global (VUEX).
    De los ejemplos puedes entender cómo usarlos.

El multilingüismo se implementa de la manera más simple: a través del filtro "lang". Especifique un idioma constante, se interpreta en texto dependiendo del idioma de la interfaz.


 v-bind:label="'BLINK_SATE' | lang" 

Para evaluar completamente las capacidades del entorno de desarrollo, necesitará un controlador preparado (cosido). Puede ensamblar el firmware usted mismo desde el proyecto o usar el firmware y la utilidad listos para usar desde aquí .


Después de flashear el controlador y conectarse a la red, debe asegurarse de que el controlador sea accesible a través de IP desde su computadora. Para hacer esto, escriba http: // [IP del controlador] en el navegador. La interfaz WEB debería abrirse.


Ahora debe especificar la dirección del controlador en el archivo config / dev.env.js


 'use strict' const merge = require('webpack-merge') const prodEnv = require('./prod.env') module.exports = merge(prodEnv, { NODE_ENV: '"development"', HW_DEVICE_URL: '"http://[IP ]"' //HW_DEVICE_URL: '"http://192.168.8.105"', //HW_DEVICE_URL: '"http://192.168.4.1"', }) 

Si se inició el servidor de desarrollo, deténgalo y reinícielo. En el futuro, después de cambiar los archivos de compilación, la configuración y el manifiesto de la aplicación, siempre reinicie el servidor de desarrollo.


Aunque cuando se trabaja en un entorno de desarrollo, se muestran todas las aplicaciones que están instaladas en la carpeta src / application, solo aquellas que realmente están instaladas en el controlador funcionarán completamente. Esta no es una característica, sino un error alfa. En el futuro, la sincronización del hardware y el entorno de desarrollo se realizará automáticamente. Pero por ahora, necesita instalar manualmente la aplicación en el controlador para que el entorno la "enganche" y la sincronice con lo que está en desarrollo.


Ensamblamos la aplicación en modo prod:


 npm run prod 

Instale las aplicaciones recopiladas en el controlador directamente. No a través del servidor de desarrollo .


Ahora puedes comenzar el desarrollo. Cualquier cambio que realice en sus archivos comenzará automáticamente a reconstruir las aplicaciones y la imagen en la pantalla cambiará (recarga en caliente). La misma regla se aplica a los scripts del controlador. Por ejemplo, puede agregar el comando depurador a la secuencia de comandos de la aplicación de parpadeo y ver el resultado.


 // Event listener // $bus - system bus interface $bus.on(function (event, content, data) { if (event === 'blink') { debugger; active = !!JSON.parse(content); } }, null); 

Ahora, cuando cambia el estado de la casilla de verificación de la aplicación Blink, el entorno de desarrollo arrojará el siguiente mensaje:



Al hacer clic en el enlace "Iniciar depurador", accederá al depurador. Se muestra la línea en la que ocurrió la parada.



El proceso de depuración en sí no es muy diferente de otros depuradores.



El depurador se divide en cuatro secciones. En el código central en sí. Dejó aplicaciones instaladas en el controlador. Su estructura y composición. Correcto, inspector. El registro se muestra a continuación. En la parte inferior izquierda se encuentra el estado actual de la comunicación con el controlador.


El entorno de depuración está en proceso de desarrollo intensivo. Hay muchas más herramientas de monitoreo y depuración para construir. Pido disculpas de antemano por posibles errores.


Desarrollo de firmware


El desarrollo del firmware se basa en el concepto propuesto por Espressif. No puedo superar la documentación nativa a este respecto.


Se ha preparado un repositorio para un inicio rápido. Contiene información de implementación. Para ver un ejemplo de uso, consulte "Implementación de una interfaz" .


El ensamblaje es muy simple y, literalmente, en 1-2 horas ya estará ensamblando el firmware sin ningún problema.


Que sigue


Además, si la plataforma es de interés para la comunidad, se planifica:


  • Desarrollo de un entorno de depuración;
  • Estandarización de nombres de interfaces, eventos, componentes;
  • Documentación detallada en la plataforma;
  • Alojamiento en la nube para cosas virtuales;
  • Repositorios de tiempo de ejecución
  • Particionamiento a varios dispositivos terminados.

Además, estoy buscando personas que deseen desarrollar la plataforma conmigo. Ya es muy grande en alcance y ambición. Asumo la misma cooperación, cuyo propósito será desarrollar la plataforma para un principio OpenSource completo.


pull- .


Referencias


ThingJS:



ThingJS:



:



FAQ


.

Source: https://habr.com/ru/post/474356/


All Articles