ThingJS v1.0-alpha


Nos últimos dois anos, desenvolvi minha própria plataforma IoT e hoje estou pronto para mostrar sua versão alfa.


Juntamente com um parceiro, criamos e suportamos dispositivos de IoT. Desmontamos mais de um ancinho no processo dessa atividade. O ThingJS nasceu não tanto do desejo como da necessidade de facilitar a vida para nós, mas ao mesmo tempo, espero, para você.


O artigo será interessante para as pessoas que estão próximas ao tópico da IoT e que já fizeram algo nesta área. Um ponto importante será que a plataforma deve interessar (de repente) desenvolvedores de JavaScript, como esse idioma é escolhido como base da plataforma. Obviamente, os desenvolvedores de C / C ++ também terão algo para ler.


Primeiro, falarei sobre os principais problemas que encontramos ao desenvolver dispositivos de IoT, depois descreverei como a plataforma lida com eles e, no final, a coisa mais chata: o vídeo , a parte técnica e você pode tocar tudo ao vivo .



Problemas de IoT:


- O problema das armas curtas


A IoT é baseada em um ecossistema. O desenvolvimento de seu conceito e arquitetura técnica é realmente muito trabalhoso. Além disso, você ainda precisa desenvolver um monte de firmware para dispositivos heterogêneos. Inventar e implementar o transporte para a troca de dados entre dispositivos em vários princípios físicos e lógicos. Expanda os recursos da nuvem. Elabore interfaces de usuário. Etc. etc.


Mesmo que um especialista individual tenha as habilidades necessárias para fazer isso, ele simplesmente não tem tempo (mãos) suficiente para implementar essa idéia. Enquanto ele vai cortar, ela se tornará obsoleta.


- O problema da torre de Babel


O desenvolvimento de um ecossistema de IoT completo exige uma pilha tecnológica muito ampla. Ser uma pilha cheia na IoT é simples ... difícil. Precisa de experiência em todos os lugares. Nem todos podem se orgulhar de uma ampla gama de conhecimentos e até experiência. E aqui a questão não está nas habilidades mentais. Esta é uma conclusão óbvia do problema da mão curta.


Criar um ecossistema verdadeiramente rico requer o trabalho de muitos especialistas bastante restritos, mas com profundo conhecimento em seu campo. Esses especialistas falam idiomas diferentes, usam padrões diferentes e geralmente entendem termos elementares de maneiras diferentes. E, como a IoT é baseada em dispositivos com recursos limitados, as comunicações efetivas são críticas para a realização do que se pretende.


- O problema da síndrome de Estocolmo


Hoje existem fornecedores que desenvolvem seus ecossistemas. São Google, Microsoft, Yandex, Megafone, MTS, etc. Alguns deles permitem que você integre suas próprias coisas nos ecossistemas deles nos termos deles. Isso abrange amplamente os problemas descritos acima. Mas cria um novo - vício. E os fornecedores gostam de alterar as condições de integração. E mais ainda, não há questão de auto-realização neste paradigma.


Soluções para problemas:


- Comunidade, vício, moda, juventude


Os problemas descritos acima, de fato, bloqueiam o acesso ao desenvolvimento da IoT para indivíduos. O desenvolvimento da plataforma foi lançado com a conscientização desses problemas. A fundação foi lançada para o desenvolvimento da plataforma através da comunidade.


Para implementar essa idéia, a plataforma, é claro, vem com uma base de código aberta e também possui um paradigma de dependência em todas as camadas.


Se você não sabe o que são vícios, é hora de conhecê-los. Mas se você tentar explicar de maneira muito simples, o módulo que você está desenvolvendo pode depender de outro que seu amigo escreve. E você acessará seu módulo através de uma interface predefinida.


Assim, ao mesmo tempo, de forma independente, muitas pessoas podem desenvolver seus próprios componentes de plataforma e reutilizar os existentes, desenvolvidos por alguém. Isso resolve fundamentalmente o problema das mãos curtas.



Além disso, o problema da "Torre de Babel" está sendo resolvido. As dependências são criadas para que os vários níveis da plataforma, desenvolvidos em diferentes idiomas, tenham um mecanismo predeterminado para criar dependências entre si.


Por exemplo, um desenvolvedor C pode tirar proveito de um componente front-end pronto, fornecendo a interface necessária. Ou, pelo contrário, o desenvolvedor front-end pode usar um componente pronto escrito em C. Isso é todos farão o que ele conhece melhor.


- Mais promessas e abstrações


O protocolo de comunicação entre dispositivos é indefinido. Em vez disso, há uma abstração - um barramento de dados. O dispositivo pode enviar um evento para o ônibus ou ouvi-lo. Não está claro quem escreve no ônibus e quem recebe antecipadamente. E quando também. A troca e entrega de dados assíncronas não são garantidas. Em geral - inferno. Sem pânico. Tão concebido.


O fato é que o ecossistema é um grupo de dispositivos separados e auto-suficientes. A qualquer momento, alguns dispositivos podem não estar disponíveis. Por várias razões. Parar a atividade de outros dispositivos se uma peça não estiver disponível não é o melhor cenário. É necessário legalizar aquilo que não pode ser evitado.


A plataforma implementa o paradigma de promessas para fornecer eventos. O primeiro dispositivo concorda com a promessa do segundo de fornecer informações. Mas não há garantias. O assinante deve decidir o que fazer em caso de fornecimento prematuro de dados para ele.


O problema da comunicação síncrona é resolvido através da transmissão de eventos através do barramento com links para canais síncronos. O protocolo de canal síncrono é determinado pelo próprio tipo de evento. Por exemplo, você pode enviar um evento com o tipo "do-render-video-stream" e como enviar câmeras IP WEB como carga útil. Assim, o destinatário saberá que você precisa reproduzir o fluxo de vídeo a partir do endereço especificado.



Mas como o ônibus funciona fisicamente? A implementação do ônibus fica com a comunidade. O pneu se expande com o transporte que seu projeto exige. Por exemplo, um evento é recebido por http e retransmitido por UART. Para todos os elementos do ecossistema, exteriormente nada mudará.


- dispositivos IoT virtuais


Para o ThingJS, algo não é apenas físico, mas também um aplicativo especial - virtual. Além disso, uma coisa física pode conter várias coisas virtuais (aplicativos) que usam os recursos de uma coisa física.


Essa abordagem permite que você unifique a interação entre o back-end condicional (controlador / servidor / nuvem, etc.) e o front-end (navegador, aplicativo etc.), bem como b2b e até f2f. Construa uma matriz, não uma hierarquia de interações.



Um exemplo simples seria uma câmera WEB, que por si só tem uma coisa virtual - uma interface de usuário. Quando o usuário acessa o endereço http://192.168.4.1 , a página WEB é aberta, onde a coisa virtual começa a "viver". A câmera (coisa física) e a página (coisa virtual) tornam-se automaticamente um ecossistema em que um barramento de dados unificado está disponível. Por meio dele, a coisa virtual se comunica com o físico. Nesse caso: a coisa física informa à virtual através do barramento o endereço do fluxo de vídeo, seu estado, etc., e a virtual mostra ao usuário o vídeo e dá os comandos necessários à coisa física.


A continuação lógica é a capacidade de hospedar coisas virtuais nas nuvens e incluí-las em um ecossistema comum. E isso, por sua vez, permite criar dispositivos virtuais com enormes recursos que resolvem problemas, por exemplo, disponíveis para IA.


Você mesmo pode criar esses dispositivos ou usar os já criados. A síndrome de Estocolmo é derrotada. Você mesmo determina do que seu projeto depende e como o desenvolverá.


Informações técnicas


Estrutura de Aplicação ThingJS



Pilha de tecnologia


A plataforma de hardware selecionada é o controlador ESP32 . A plataforma foi projetada como independente de hardware. Infelizmente, não houve tempo para particionar em outros dispositivos.


Para o desenvolvimento do firmware, são utilizadas as ferramentas recomendadas da Espressif . O firmware é desenvolvido em C. O coletor cmake. O projeto utiliza o conceito de componente, também promovido pela Espressif.


Além do esp-idf, o Mongoose WEB Server é usado , assim como um interpretador JavaScript modificado do Mongoose mJS .


Para o desenvolvimento de aplicativos, o JavaScript é usado com a estrutura do VUE 2. Crie aplicativos usando o webpack. O gerenciador de pacotes é npm. A CLI do VUE foi usada como base para o ambiente de desenvolvimento.


A fim de padronizar a visualização de aplicativos e facilitar as dores da criatividade da interface do usuário, o pacote vuetifyjs está incluído na plataforma.


Recursos do ambiente de desenvolvimento


Para desenvolvedores de JavaScript (coisas virtuais):


  • IDE recomendado - WEBStorm;
  • Todos os lucros que o VUE CLI e o IDE oferecem;
  • Depuração intra-sistema de aplicativos (depurador mJS no controlador);
  • O MJS implementa o comando debugger, que permite chamar o depurador em um local arbitrário;
  • Upload quente de arquivos atualizados para o controlador durante o desenvolvimento (os desenvolvedores JavaScript já não podem viver sem esse recurso);
  • O desenvolvimento do tempo de execução é emparelhado com um controlador real. Você programa e, ali mesmo, vê o resultado no hardware;
  • ESLint configurado para entender os objetos da plataforma.

Para desenvolvedores C (coisas físicas):


  • IDE recomendado - CLion;
  • Todos os lucros esp-idf e IDE;
  • A plataforma é dividida em componentes como parte do conceito esp-idf;
  • Fácil integração com a plataforma de componentes nativos.

Dispositivos suportados


No momento, apenas o ESP32 é suportado. O chip é popular devido à sua disponibilidade com características técnicas surpreendentes. Com base nisso, muitos dispositivos IoT prontos foram criados que podem ser usados ​​no ThingJS.


Comparação com concorrentes


Sugiro não correr tão longe. Não me atrevo a chamar concorrentes de plataformas comerciais. E o código aberto aparece e desaparece sem deixar vestígios visíveis. Portanto, não fiz uma comparação. No entanto, se alguém quiser, estou pronto para postar o resultado de seu trabalho aqui.


Início rápido


Eu só tenho que assistir



Eu quero tentar


Para experimentar a plataforma em hardware real, você precisará de qualquer dispositivo baseado no ESP32 com flash de 4mb e capacidade de flash via USB. Mas a placa principal ESP32 v2 é mais adequada.



Você pode comprar essas coisas sem problemas no Aliexpress ou no Ebay. Além disso, existem até escritórios de representação na Rússia. Eu pessoalmente compro em São Petersburgo .


Para testar a operação do aplicativo de teste “Blink”, você precisa conectar um LED. Algumas versões das placas têm um LED pré-instalado conectado ao GPIO2. Se você tem uma placa assim, não pode fazer nada. O piscar deve funcionar sem movimentos desnecessários. Se você tiver apenas um diodo (fonte de alimentação), precisará conectar o diodo indicador sozinho. Isso não é nada complicado.


Você precisará de qualquer LED indicador e resistência de 1 a 5K.



A única coisa que resta é implantar o pacote do usuário no dispositivo. Você pode pegar aqui . As instruções de implantação estão localizadas lá.




O Blink é um ecossistema simples que consiste em um dispositivo virtual que implementa a interface do usuário e um físico. Um dispositivo virtual inicia a partir de um dispositivo físico ao acessá-lo através de um navegador.


O script é simples. Ao instalar o aplicativo em um dispositivo físico, o LED (anteriormente conectado a ele) começa a piscar na frequência de 1 Hz. O usuário pode ativar ou desativar o diodo piscante na interface. Você pode assistir ao vídeo na seção "Só posso assistir".


As fontes estão no repositório src / applications / blink. Para coletar o piscar de olhos e brincar com ele, você só precisa deste repositório. Verifique se você já possui git, npm e nodejs instalados.


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

Se tudo correu bem, você terá algo como o seguinte:



Parabéns! Você criou seu primeiro aplicativo ThingJS. Você pode encontrá-lo na pasta dist / apps / blink e tentar instalá-lo imediatamente no dispositivo, guiado pelo vídeo na seção "Só posso assistir" .



FicheiroDescrição do produto
scripts / blink.jsO script que está instalado no controlador
blink.jsPonto de montagem do componente do aplicativo
Blink.vueComponente VUE que implementa a interface do usuário
favicon.svgÍcone do aplicativo
langs.jsPacote de idiomas do aplicativo
manifest.jsonManifesto de aplicativo

Você pode se familiarizar com todos os detalhes do aplicativo. Vou me concentrar em vários arquivos.



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

Como o nome do arquivo indica, este é o manifesto do aplicativo. Possui metadados gerais sobre os quais é fácil adivinhar. Além deles, existem três blocos importantes. Vamos olhar para eles de perto:



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

O bloco descreve toda a base de componentes do aplicativo. O campo "origem" aponta para o ponto de montagem do componente (consulte blink.js) e é o ponto de entrada do assembly para o webpack ( entrada ). Assim, cada componente será emitido em um pacote separado. Este pacote será carregado conforme necessário ( carregamento lento ).


Uma estrutura importante é intent_filter . Se você programar para Android, encontrará algo familiar para você. E não cometa um erro. O sistema gera eventos de interface e serviço aos quais o componente assina. Se ocorrer um evento que atenda às condições de filtragem, o componente será carregado e o controle será transferido para o ponto de montagem.


Nesse caso, o componente "blink-app" é inscrito no evento de inicialização do componente de interface principal do aplicativo. Quando o iniciador inicia o aplicativo, este componente será introduzido.


Se você modificar o manifesto alterando a linha


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


, depois da montagem e instalação, verifica-se que o aplicativo parou de abrir na área de trabalho. Mas um novo "bloco" apareceu na seção "Configurações". Ao mesmo tempo, nada mudou funcionalmente.


Assim, indicamos ao iniciador que esse componente é um elemento de interface para personalizar nosso aplicativo. E esse componente começou a aparecer nas configurações.



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

Esse bloco é semelhante em função ao bloco "components", mas descreve a base de componentes do aplicativo no lado do controlador.


Indica claramente o ponto de entrada. No campo "entrada". Separadamente, prestarei atenção que, ao instalar o aplicativo, o script não inicia imediatamente. É iniciado apenas quando ocorre um dos eventos nos quais o script está registrado.


O campo "assinaturas" é responsável por assinaturas. Agora indica dois eventos:


  • $ -script-restart - ocorre quando o sistema é iniciado ou reiniciado;
  • blink é um evento personalizado relevante para o ecossistema do blink.

No bloco "modules", segue uma descrição da composição dos scripts. Vou observar dois campos:


  • hot_reload - se esse campo estiver definido como true, quando um arquivo for alterado no modo de desenvolvimento, ele será automaticamente baixado no controlador (hot reload);
  • otimizar - se verdadeiro, ao criar o projeto, o script será otimizado e agregado.


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

Você provavelmente já percebeu que, ao instalar o aplicativo, precisa selecionar o pino no qual o LED piscará. No entanto, por padrão, ele já está selecionado como GPIO2. Este bloco é responsável por essas configurações.


Neste bloco, as dependências são indicadas. Nesse caso, para que o aplicativo funcione, ele precisa fornecer uma interface com o tipo "bit_port". Essa interface é um requisito obrigatório (obrigatório = verdadeiro) e, por padrão, GPIO2 é especificado (padrão = 2). Ele será projetado no script com o nome "piscar".


Ao instalar o aplicativo, o perfil do equipamento no qual os scripts serão implantados é levado em consideração. Esse perfil lista as interfaces disponíveis e os recursos de hardware disponíveis para eles (em particular, pinos e suas combinações). Verifica a compatibilidade de requisitos e equipamentos. Se o equipamento puder atender aos requisitos do aplicativo, será mostrado ao usuário um esquema de alocação de recursos, onde os recursos primários são alocados automaticamente, levando em consideração as recomendações do manifesto. I.e. desse mesmo campo "padrão".


Assim, vários aplicativos podem ser instalados em um dispositivo, que podem compartilhar recursos de hardware entre si.



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

O arquivo é o ponto de montagem do componente anunciado no manifesto (consulte manifest.js / components). Ele grava o VUE do componente 'blink-app' por meio do método de abstração $ exportComponent e também registra o pacote de idiomas.


Você pode perguntar - por que essas dificuldades? Por que não registrar imediatamente o componente VUE especificado na fonte? O fato é que o manifesto descreve componentes públicos. Esses componentes podem ser solicitados por aplicativos de terceiros (dependências de tempo de execução). O ponto de montagem, por sua vez, pode registrar componentes relacionados (para uso interno), bem como serviços. Ou seja, prepare o ambiente do 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 }; } }; 

O código fala por si. Quando a propriedade “blink_state” é alterada, uma mensagem é enviada ao barramento ($ bus) com o valor atual. Isso é tudo o que você precisa fazer para que o script no lado do controlador receba o comando desejado.



 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); 

Em geral, o código é muito semelhante ao uso clássico de um timer em JavaScript. Exceto que não está neste dialeto do JavaScript. É implementado na plataforma. Conheça este mJS . Você pode aprender mais sobre isso na página oficial do projeto.


Para as necessidades da plataforma, o dialeto é finalizado. Os temporizadores foram introduzidos, assim como um comando útil como "depurador". Bem, o próprio depurador. Mais sobre isso separadamente na seção "Ambiente de desenvolvimento" .


Preste atenção aos objetos globais da plataforma. Eles são nomeados com o caractere "$".


  • $ res - contém recursos alocados ao script;
  • $ bus - interface de barramento .

Porque o aplicativo solicitou uma interface com o tipo “bit_port” (consulte profile.json / require) e o nome “blink”, foi atribuído a ele como $ res.blink. A interface implementa apenas três funções:


  • set (value) - define o nível GPIO
  • get () - obtém o nível atual do GPIO
  • direction (value) - define o modo GPIO

Para a função de direção, as constantes disponíveis são descritas na mesma interface $ res.blink.: DIR_MODE_DISABLE; DIR_MODE_DEF_INPUT; DIR_MODE_DEF_OUTPUT; DIR_MODE_INPUT_OUTPUT_OD; DIR_MODE_INPUT_OUTPUT.


A inscrição em eventos de barramento é feita através do método $ bus.on. Nesse caso, todos os eventos nos quais o script está inscrito chegarão ao manipulador. O manipulador aceita três parâmetros:


  • evento - identificador de evento . Nesse caso, apenas dois são possíveis: "$ -script-restart" e "piscar". Dos quais apenas um é processado - pisque. É necessário assinar o segundo para que o script seja iniciado imediatamente na inicialização do sistema.
  • conteúdo - os dados podem vir com o evento. Seu tamanho é limitado a 126 bytes, levando em consideração o tamanho do identificador de evento.
  • data - dados transmitidos ao se inscrever no evento como um segundo parâmetro. E neste caso, eles são nulos.

As interfaces são extensíveis. Abaixo, você encontrará uma descrição de como criar sua própria interface.


Implementação de interface


O ThingJS permite expandir os recursos de hardware e serviço disponíveis por meio de interfaces especiais. Você pode criar independentemente uma interface que implementará qualquer complexidade, precisão, carga, etc. funcional.


Por exemplo, você pode implementar uma interface de integração com seu serviço de nuvem. Ou um processo assíncrono em segundo plano com o qual o script poderá trocar mensagens. Bem, ou implemente o suporte de exibição. Será igualmente fácil de fazer e usar. Você e os outros. Verdade, para isso você precisa conhecer C.


Considere a implementação da interface bit_port, usada no exemplo Blink. Para iniciar, você precisa implantar o projeto de liberação alfa do modelo ThingJS . A documentação de implantação está no próprio projeto.


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

O projeto inclui componentes:


  • ThingJS-boards - contém configurações de dispositivos. Até agora, apenas o ESP32_CORE_BOARD V2 e compatível;
  • ThingJS-extern - bibliotecas de projetos de terceiros que o ThingJS usa;
  • ThingJS-core - núcleo da plataforma;
  • ThingJS-front - ambiente de desenvolvimento de aplicativos;
  • ThingJS-stdi - interfaces padrão.

Estamos interessados ​​no projeto ThingJS-stdi. Sua estrutura é a seguinte:


FicheiroDescrição do produto
implementação / tgsi_bit_port.cImplementação da interface Bit_port
implementação / tgsi_bit_port.hArquivo de cabeçalho da interface Bit_pro
CMakeLists.txtscript de construção do cmake
README.md
sdti_utils.hAjudantes
thingjs_stdi.cPonto de montagem da interface
thingjs_stdi.hArquivo de cabeçalho do ponto de montagem

De fato, estamos interessados ​​apenas em um arquivo - deployment / tgsi_bit_port.c. Ele contém tudo o que requer uma explicação separada.


 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); } 

A função thingjsBitPortRegister registra um componente no núcleo do ThingJS. Para fazer isso, ele chama a função thingjsRegisterInterface, para a qual passa uma estrutura com uma descrição da interface.


  • tipo - identificador de interface. É ele quem é especificado como o tipo no arquivo manifest.json do aplicativo;
  • constructor - link para o construtor de interface. A função é chamada toda vez que você precisa criar uma nova instância da interface;
  • cases é uma matriz que descreve possíveis recursos de hardware que a interface pode usar para seu trabalho. Nesse caso, esses são GPIOs únicos. Mas suas combinações ou dependências podem ser descritas separadamente.

O construtor de interface monta a interface na 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; } 

Como os parâmetros são passados:


  • mjs - contexto de execução global;
  • params - parâmetros de inicialização da interface. Nesse caso, este é o número GPIO.

Um objeto "interface" mJS é criado, onde os métodos e propriedades da interface são montados:


  • gpio - propriedade somente leitura na qual o número de GPIO usado é armazenado;
  • set - método para definir o nível do sinal;
  • get - um método para obter o nível atual do sinal;
  • direção - definindo o modo GPIO;

Além disso, são montadas constantes com as quais os scripts podem operar (DIR_MODE_DISABLE, DIR_MODE_DEF_INPUT, etc.).


Depois de criar a interface, ela é montada sob um identificador específico (no exemplo Blink, é "blink") no objeto global $ res. Um exemplo de uso pode ser encontrado na seção Blink ( scripts / blink.js ).


Você pode formatar interfaces em componentes ou pacotes separados. Isso permitirá que você monte o firmware como lego.


Ambiente de desenvolvimento


Desenvolvimento de aplicações


O ambiente de desenvolvimento de aplicativos é baseado na CLI VUE, que foi refinada para atender às necessidades da plataforma ThingJS. Este é um garfo duro, incl. vale a pena aguardar novos recursos do VUE CLI, se facilitarem bastante a vida.


Para implantar o ambiente, é necessário clonar o projeto de liberação alfa do ThingJS-front . Verifique se você já possui git, npm e nodejs instalados.


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

Ao desenvolver, recomendo usar o IDE WEBStorm.


A composição e a estrutura do projeto são herdadas do VUE CLI. Vou refletir diferenças significativas:


  1. Scripts de construção reformulados na pasta de construção.
  2. Uma variável de ambiente “HW_DEVICE_URL” foi adicionada à configuração do ambiente dev (config / dev.env.js). É necessário especificar um link para o dispositivo físico com o qual você trabalhará.
  3. A pasta do sistema src / applications apareceu. Ele contém aplicativos que serão criados automaticamente. Em particular, ele contém dois aplicativos: ante (iniciador) e pisca (aplicativo).
  4. Tudo acima da pasta src / applications é considerado módulos e recursos da plataforma. Obviamente, você pode fazer alterações neles, mas nesse caso, eles aparecerão no controlador somente depois de piscá-lo. T.ch. A menos que você defina metas para si mesmo, é melhor não tocá-las.

Para teste, você pode iniciar imediatamente o servidor dev. Embora você não possa desenvolver completamente sem o hardware físico, isso não interfere no desenvolvimento da interface. E assim, o servidor dev inicia:


 npm run dev 

O resultado deve ser algo como isto:



Ao abrir o navegador e digitar http://0.0.0.0:8080 na barra de endereços, você verá a plataforma no modo de desenvolvimento:



O processo de desenvolvimento de interface em si não é muito diferente do desenvolvimento front-end clássico no VUE. Exceto que existem objetos de plataforma global dos quais você precisa estar ciente:


  • $ const - contém constantes da plataforma, bem como pacotes de idiomas;
  • $ bus - barramento de dados;
  • $ store - armazenamento global (VUEX).
    A partir dos exemplos, você pode entender como usá-los.

O multilinguismo é implementado da maneira mais simples - através do filtro "lang". Especifique uma constante de idioma, que será interpretada em texto, dependendo do idioma da interface.


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

Para avaliar completamente os recursos do ambiente de desenvolvimento, você precisará de um controlador preparado (costurado). Você pode montar o firmware a partir do projeto ou usar o firmware e o utilitário prontos aqui .


Depois de piscar o controlador e conectar-se à rede, você precisa garantir que o controlador esteja acessível via IP do seu computador. Para fazer isso, digite http: // [IP do controlador] no navegador. A interface WEB deve abrir.


Agora você precisa especificar o endereço do controlador no arquivo 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"', }) 

Se o servidor de desenvolvimento foi iniciado, pare-o e reinicie-o. No futuro, depois de alterar os arquivos de construção, a configuração e o manifesto do aplicativo, sempre reinicie o servidor dev.


Embora ao trabalhar em um ambiente de desenvolvimento, todos os aplicativos que estão na pasta src / application como instalados sejam exibidos, apenas aqueles realmente instalados no controlador funcionarão totalmente. Este não é um recurso, mas um erro alfa. No futuro, a sincronização do hardware e do ambiente de desenvolvimento ocorrerá automaticamente. Mas, por enquanto, você precisa instalar manualmente o aplicativo no controlador para que o ambiente o conecte e sincronize com o que está em desenvolvimento.


Montamos o aplicativo no modo prod:


 npm run prod 

Instale os aplicativos coletados diretamente no controlador. Não através do servidor de desenvolvimento .


Agora você pode iniciar o desenvolvimento. Quaisquer alterações feitas nos arquivos começarão automaticamente a reconstruir os aplicativos e a imagem na tela será alterada (recarga a quente). A mesma regra se aplica aos scripts do controlador. Por exemplo, você pode adicionar o comando debugger ao script do aplicativo piscar e ver o resultado.


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

Agora, quando o estado da caixa de seleção do aplicativo Blink mudar, o ambiente de desenvolvimento emitirá a seguinte mensagem:



Clicar no link "Iniciar depurador" o levará ao depurador. A linha na qual a parada ocorreu é exibida.



O processo de depuração em si não é muito diferente de outros depuradores.



O depurador é dividido em quatro seções. No próprio código central. Aplicativos instalados à esquerda no controlador. Sua estrutura e composição. Certo, inspetor. O log é exibido abaixo. No canto inferior esquerdo está o status atual da comunicação com o controlador.


O ambiente de depuração está em processo de desenvolvimento intensivo. Existem muitas outras ferramentas de monitoramento e depuração a serem construídas. Peço desculpas antecipadamente por possíveis erros.


Desenvolvimento de Firmware


O desenvolvimento do firmware é baseado no conceito proposto pela Espressif. Não consigo superar a documentação nativa a esse respeito.


Um repositório foi preparado para um início rápido. Ele contém informações de implantação. Para um exemplo de uso, consulte "Implementando uma interface" .


A montagem é muito simples e, literalmente, em 1-2 horas, você já estará montando o firmware sem problemas.


O que vem a seguir?


Além disso, se a plataforma é de interesse da comunidade, está planejada:


  • Desenvolvimento de um ambiente de depuração;
  • Padronização de nomeação de interfaces, eventos, componentes;
  • Documentação detalhada na plataforma;
  • Hospedagem em nuvem para coisas virtuais;
  • Repositórios de tempo de execução
  • Particionando em vários dispositivos acabados.

Além disso, estou procurando pessoas que gostariam de desenvolver a plataforma comigo. Já é muito grande em escopo e ambição. Eu assumo a cooperação igual, cujo objetivo será desenvolver a plataforma para um OpenSource de pleno direito.


pull- .


Referências


ThingJS:



ThingJS:



:



FAQ


.

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


All Articles