Sony Arouje

a programmer's log

Archive for the ‘.NET’ Category

Expo react-native development in Docker

leave a comment »

I spent most of my free time learning developing applications in different platforms. Recently I was spending time in Expo, a platform to build react-native apps. Expo is a pretty good platform to kick start your react native development. One of the difficulty I always face is upgrading the versions, for e.g. some times expo releases multiple updates in a month. When upgrading in my Windows machine, there could be issues, either a file lock or some thing else. These installations issues leads to frustrations and fire fighting to return to a working state. Recently my friend Sendhil told me, how he use VS Code to remote develop using containers. I decided to take a look at it.

I kept myself away from docker for some time. Decided to try out docker again. It took me few mins to up and running a docker image maintained by node. Next step was to install the expo-cli and other dependencies to run my expo test application. I had to over come several errors popped up when running expo code in a container. Spend hours reading forums and posts to resolve it one by one. Here is the Dockerfile I came up, which can be used to develop any expo based applications.

The below workflow holds good for any kind of node or react or react-native, etc developments.

Dockerfile

FROM node:10.16-buster-slim
LABEL version=1.0.0

ENV USERNAME dev
RUN useradd -rm -d /home/dev -s /bin/bash -g root -G sudo -u 1005 ${USERNAME}

EXPOSE 19000
EXPOSE 19001
EXPOSE 19002

RUN apt update && apt install -y \
    git \
    procps

#used by react native builder to set the ip address, other wise 
#will use the ip address of the docker container.
ENV REACT_NATIVE_PACKAGER_HOSTNAME="10.0.0.2"

COPY *.sh /
RUN chmod +x /entrypoint.sh \
    && chmod +x /get-source.sh

#https://github.com/nodejs/docker-node/issues/479#issuecomment-319446283
#should not install any global npm packages as root, a new user 
#is created and used here
USER $USERNAME

#set the npm global location for dev user
ENV NPM_CONFIG_PREFIX="/home/$USERNAME/.npm-global"

RUN mkdir -p ~/src \
    && mkdir ~/.npm-global \
    && npm install expo-cli --global

#append the .npm-global to path, other wise globally installed packages 
#will not be available in bash
ENV PATH="/home/$USERNAME/.npm-global:/home/$USERNAME/.npm-global/bin:${PATH}"

ENTRYPOINT ["/entrypoint.sh"]
CMD ["--gitRepo","NOTSET","--pat","NOTSET"]

VS Code to develop inside a container

To enable VS Code to develop inside a container, we need to Install Remote Development Extension pack. Here is the more detailed write up from MS

To enable remote development we need two more files in our source folder.

  • docker-compose.yml
  • devcontainer.json

docker-compose.yml

version: '3.7'

services:
  testexpo:
    environment:
      - REACT_NATIVE_PACKAGER_HOSTNAME=10.0.0.2
    image: sonyarouje/expo-buster:latest
    extra_hosts:
      - "devserver:10.0.0.2"
    command: "--gitRepo sarouje.visualstudio.com/_git/expotest --pat z66cu5tlfasa7mbiqwrjpskia"
    expose:
      - "19000"
      - "19001"
      - "19002"
    ports:
      - "19000:19000"
      - "19001:19001"
      - "19002:19002"
    volumes:
      - myexpo:/home/node/src
volumes:
  myexpo:

  • REACT_NATIVE_PACKAGER_HOSTNAME: Will tell react-native builder to use the configured ip when exposing the bundler, else will use the docker container’s ip and will not be able to access from your phone.
  • command: Specify your git repo to get the source code and the pat code. When running docker-compose up, docker container will use these details to clone your repo to /home/dev/src directory of the container.
  • volumes: Containers are short lived and stopping the container will loose you data. For e.g. once the container is up we might install npm packages. If the packages are not able to persist then we need to reinstall packages every time we start the container. In order to persist the packages and changes, docker-compose creates a named volume and keep the files of /home/dev/src in the volume and can be accessible even after docker restart.

Keep in mind ‘docker-compose down’ will remove the volume and we need to reinstall all the packages again.

devcontainer.json

Create a new folder named .devcontainer and inside the new folder create a file named devcontainer.json. Below is the structure of the file.

{
    "name": "expo-test",
    "dockerComposeFile": "../docker-compose.yml",
    "service": "expo-test",
    "workspaceFolder": "/home/dev/src/expotest",
	"extensions": [
       "esbenp.prettier-vscode"
    ]
    "shutdownAction": "stopCompose"
}
  • dockerComposeFile: will tell where to find the docker-compose.yml file 
  • service: Service configured in docker-compose.yml file
  • workspaceFolder: Once VS Code attached to the container, will open this workspace folder.

    extensions: Mention what all the extensions need to be installed in VS Code running from the container.

Work flow

  • Download the latest version of docker
  • Open powershell/command prompt and run ‘docker pull sonyarouje/expo-buster’
  • Open your source folder and create docker-compose.yml and .devcontainer/devcontainer.json file
  • Modify docker-compose.yml and give the git repo and pat, etc
  • Open VS Code in source folder. VS Code will prompt to Reopen in Container, click Reopen in Container button. Wait for some time, and VS Code will launch from the container.
  • Once launched in container, all your code changes will be available only in the container. Make sure to push your changes to git before exiting the container.

Advantages of containerized approach

We can spawn a new container at ease and test our code against any new version of libraries we are using. We don’t need to put our dev machine at risk. Any break or compilation issues, we can always destroy the container and go back to the dev container and proceed with our development. No need to restore our dev machine to a working state. If the upgrade succeed then we can always destroy the current dev container and use the new container as the development container. No more hacking with our current working container.

Where is the source?

All the dockerfiles and scripts are pushed to git. Feel free to fork it or give me a pull request in case of any changes. I created two versions of docker file, one for alpine and one for buster. As of now stable VS Code release wont support alpine but you can always switched to VSCode insider build to use alpine.

Docker image is published to docker hub, can be pulled using sonyarouje/expo-buster or sonyarouje/expo-buster:3.0.6. Here 3.0.6 is the version of expo-cli.

      Advertisements

      Written by Sony Arouje

      August 2, 2019 at 7:18 pm

      Posted in .NET

      Aeroponic V3 – controlled by Arduino an overview

      with 9 comments

      Last couple of months I was building a new version of my Aeroponic controlling system. This time I dropped Raspberry pi and moved to Arduino. One of the reason I moved to Arduino is, it’s a micro controller and has no OS. So the system will not crash, in case of power failures. Raspberry pi is on the other hand runs Linux and frequent power failures might damage the OS. The new system has all the features of my old version, plus some additional features.

      Overview

      I decided to use Arduino Nano, for my development. Nano has a small foot print and can plug into a PCB. I also designed a PCB to hold all the pieces together, will see the PCB shortly.

      I went through several iterations of PCB design. Initially I started with onboard relay modules, later I decided to remove on board relay modules and plug external relay modules. The reason to use external relay is, I can change the relays depends on the water pump’s ampere. Also I can easily change relays if it got fried.

      Mobile Application: Just like last version I created an Android app to control the system but this time I wrote a native app, previously I used Cordova to build the app.

      Communication: Mobile app and Arduino communicates via bluetooth. I used HC-06 bluetooth module. To make the system simple, I skipped WiFi module. May be in later version I can include WiFi or I can use Arduino MKR1000 which has inbuilt WiFi.

      Power: The system runs in 12V DC. The board can be powered in two different ways, either connect a 12V power adapter with a standard 2.1mm barrel jack or use a DC converter and supply power via normal screw terminal.

       

      Features of the Controller system

      Controlling Water Pump: One of the crucial part of Hydroponic/Aeroponic system is the cycling of water in periodic intervals. A water pump is used to cycle the water. The controller should be able to switch on motor in a particular interval and keep it on for a configured time. Say run motor every 30 mins and keep it on for 3 mins. This settings can be configured from the mobile application.

      Nutrient Feeder: In Aeroponic/Hydroponic the fertilizers (called as nutrients) are mixed into the water. In normal scenario we need to add it manually, the system uses two dosage pumps to add nutrients. We can add nutrients two way, either via the mobile app or by manually pressing a button. Through mobile app, we can specify how may ml of nutrients need to mixed to water.

      Nutrient Mixer: Used a small wave maker to mix the nutrients while adding it.

      Maintain Reservoir Water Level: One of the important thing to consider is, the water pump should not dry run, if it does then ready to buy a new one. In this version, used water level sensors to know the water level. The system used a solenoid valve, which is connected to a water source. When the water level goes down to a set level, system will activate the valve and start filling the reservoir. Once the water reaches a set level, system will switch off the valve.

      PCB

      I spent a lot of time in designing the board and come up with a very simple board with pluggable external relay modules. I am a beginner in PCB and electronics world. I had to spend my nights assembling the system in a bread board to see how each components behave. For me programming is easy but not playing with electronic components. At last I come up with a board design. Next big task was to find a shop to manufacture the prototype board. I was in touch with so many vendors and some never responded. I choose Protocircuits to do the PCB manufacturing.

      Snapseed (55) 

      Protocircuits manufactured a beautiful board for me. I etched several boards at home but this was awesome. I spend another night to solder the components to the board, see the assembled board below.

       

      Snapseed (53)

       

      Here Arduino and Bluetooth modules are not soldered instead plugged to a female header. External relay modules can be plugged via screw terminals.

      About Protocircuits

      I had a very good experience with Protocircuits. They are very professional in dealing with me and answering all my queries. I should thank Jeffrey Gladstone, Director Business development for his prompt replies and answering to all my queries. If anyone want to prototype a board, I highly recommend Protocircuits. You can reach them at info@protocircuits.in

      Buying Components: I highly recommend to buy any electronic components directly from the market than from any ecom providers. I did a comparison with price in the market and some online electronic shops and the price was very less in market. Take an e.g. of a chip 24LC256, in ebay.in it cost 100rs for one, from market I bought the same for 40rs. If you are in Bangalore, take a ride to SP Road and I am sure you will get all the components you want.

      Written by Sony Arouje

      April 23, 2016 at 1:34 am

      Posted in .NET

      My IoT Experimental desk

      leave a comment »

      Snapseed (30)

      Written by Sony Arouje

      February 13, 2016 at 5:33 pm

      Posted in .NET

      Node js error handling using modules inherited from EventEmitter

      leave a comment »

      In node js most of the operations are asynchronous and normal try-catch will not work. In case of any error and we didn’t handle it properly, our node process will crash. In this post I will explain how to handle errors properly using EventEmitter.

      In this e.g. we are going to read some data from a SQLite db, I use dblite as my node module to deal with SQLite db. For this e.g. I created a UserRepository module and inherited from EventEmitter

      UserRepository.js

      var dblite = require('dblite');
      var util = require('util');
      var EventEmitter = require('events').EventEmitter;
      
      var UserRepository = function () {
          var self = this;
      
          self.getUser = function (userid, callback) {
              db.query('select * from USER where USER_ID=:id', [], { id: userId },
              function (err, rows) {
                  if (err)
                      publishErr(err); 
      
                  callback(rows);
              });
          };
      
          var publishErr = function (err) {
              self.emit('error', err);
          };
      };
      
      
      util.inherits(UserRepository, EventEmitter);
      module.exports = UserRepository;

       

      Using util.inherits, we inherits the UserRepository module from EventEmitter. Later we export that module to use in other node modules. The publishErr() function will emit an ‘error’ event in case of any error and calling module can subscribe to that event and handle the error.

      Let’s use the above module in another node module. Say an express rest api.

      restApi.js

      var express = require('express');
      var bodyParser = require('body-parser')
      
      var UserRepository = require('./UserRepository');
      var userRepo = new UserRepository();
      
      var app = express();
      app.use(bodyParser.json());
      app.listen(8080);
      
      userRepo.on('error', function (err) {
          console.log(err);
      });
      
      app.get('/users/;id', function (req, res) {
          userRepo.getUser(req.params.id, function (record) { 
              res.send(record);
          });
      
      });

       

      Let’s go through the lines in bold.

      Here we are creating the instance of UserRepository module.

      var UserRepository = require('./UserRepository');
      var userRepo = new UserRepository();

      The calling module should subscribe for the error event, that’s what we are doing here. I am just writing the error to the console. You can do whatever you want with that err object.

      userRepo.on('error', function (err) {
          console.log(err);
      });

       

      This way we can ensure that our errors are handled properly in an elegant way.

      Node js has an uncaughtException event and use it as a last resort.

      process.on('uncaughtException', function (err) {
          console.log(err);
      })

      Written by Sony Arouje

      November 7, 2014 at 5:47 pm

      Posted in .NET

      Chat application using SignalR 2.1

      with 8 comments

      Around two years ago I published a post about SignalR. Recently some readers requested an updated post using SignalR 2.1, here is the updated one.

      For this post I created a very simple chat application that hosted in IIS, developed in .NET 4.5. Below is the project structure.

      • SignalrTracer.ChatServer: An empty ASP.NET Web Application which host the SignalR hub.
      • SignalrTracer.Publisher: A class library project that has SignalR hubs. I created this project just to isolate SignalR hubs from the ChatServer.
      • SignalrTracer.ChatClient: Another empty ASP.Net Web Application act as the client.

       

      SignalrTracer.Publisher

      As I mentioned above, this project contains the SignalR hubs. We can add SignalR framework using Nuget package manager.

      Open Package Manager Console from Tools->Nuget Pacakger Manager and choose SignalrTracer.Published as the Default Project in the console window, then enter

      PM> Install-Package Microsoft.AspNet.SignalR.Core

      The command will add the SignalR and dependent frameworks. It’s time to create our chat hub.

      ChatHub.cs

      using Microsoft.AspNet.SignalR;
      namespace SignalrTracer.Publisher
      {
          public class ChatHub:Hub
          {
              public void Subscribe(string chatId)
              {
                  Groups.Add(Context.ConnectionId, chatId);
              }
      
              public void Publish(string toChatId, string message)
              {
                  Clients.Group(toChatId).flush(message);
              }
          }
      }
      

       

      SignalR 2.1 relies on OWIN to host it. For that we need to create a Startup class as shown below.

      using Microsoft.Owin;
      using Owin;
      using Microsoft.AspNet.SignalR;
      [assembly: OwinStartup(typeof(SignalrTracer.Publisher.Startup))]
      namespace SignalrTracer.Publisher
      {
          public class Startup
          {
              public void Configuration(IAppBuilder app)
              {
                  // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
                  var hubConfig = new HubConfiguration();
                  hubConfig.EnableDetailedErrors = true;
                  hubConfig.EnableJSONP = true;
                  app.MapSignalR("/chatserver", hubConfig);
      
                  app.Run(async context =>
                  {
                      await context.Response.WriteAsync("Chat server started");
                  });
              }
          }
      }
      

      That’s it we created our SignalR hub. Let’s host it in our ChatServer.

      SignalrTracer.ChatServer

      This project is a OWIN host, to do that we need to refer another Nuget package called Microsoft.Owin.Host.SystemWeb.

      Open the Nuget Package Manager Console and set Default project as SignalrTracer.ChatServer, then enter

      PM> Install-Package Microsoft.Owin.Host.SystemWeb

      Once all the package installed, just refer SignalrTracer.Publisher project and run the project. If every thing is fine then you can see an Internet Explorer with a string Chat server started. This means SignalR hub is up and running and any clients can connect now.

       

      SignalrTracer.ChatClient

      I used Javascript to connect to SignalR server. Open Nuget Package Manager Console and enter

      PM> Install-Package Microsoft.AspNet.SignalR.JS

      It will install JQuery and JQuery extension of SignalR client. I created an index.html and added the code below.

      <!DOCTYPE html>
      <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
          <script src="Scripts/jquery-1.6.4.min.js"></script>
          <script src="Scripts/jquery.signalR-2.1.2.min.js"></script>
          <script type="text/javascript">
          $(function () {
              var connection = $.hubConnection('http://localhost:35144/chatserver');
              var proxy = connection.createHubProxy('ChatHub');
              connection.start()
                      .done(function () {
                          $('#messages').append('<li>Connected to chat</li>');
                      })
                      .fail(function () { alert("Could not Connect!"); });
      
              proxy.on('flush', function (msg) {
                  $('#messages').append('<li>' + msg + '</li>');
              });
      
              $("#send").click(function () {
                  proxy.invoke('Publish', $("#sendTochatId").val(), $("#message").val());
              });
      
              $("#connect").click(function () {
                  proxy.invoke('subscribe', $("#chatId").val());
                  $('#messages').append('<li>subscribed to chat</li>');
              });
          });
          </script>
      
          <title></title>
      </head>
      <body>
      
          <label>Chat id</label> <input type="text" id="chatId" /><input type="button" id="connect" value="Connect" /><br />
          <label>Send To</label> <input type="text" id="sendTochatId" /><br />
          <label>Message</label> <input type="text" id="message" />
          <input type="button" id="send" value="Send"/>
          <div>
              <ul id="messages"></ul>
          </div>
      </body>
      </html>
      

       

      You might need to change the url of hubConnection marked in bold.

      Once the connection established messages section will get appended with ‘Connected to chat’ message.

      Enter a unique Id in Chat Id text and click Connect, open multiple window and connect with different chat id’s.

       

      As you can see it’s a very basic and simple chat system based on SignalR.

      Source Code

      Happy coding…

      Written by Sony Arouje

      September 18, 2014 at 12:49 am

      Posted in .NET

      Tagged with ,

      Compile SQLite for WinRT with FTS4 unicode61 support

      leave a comment »

      I was experimenting with the FTS3/FTS4 feature of SQlite in a WinRT app. The default tokenizer ‘simple’ wont tokenize special character like $, @, etc. The solution is to use ‘unicode61’ tokenizer. Unfortunately the SQLite installer for WinRT8.1 comes without unicode61 tokenizer. I searched a lot to get a SQlite WinRT build that supports unicode61 but I was not lucky enough to get one, so I decided to build one myself.

      Tim Heuer have a great post explaining about creating a build of SQLite for WinRT, I went through that and acquired all the tools to build, including the SQLite source code. I did exactly the same way Tim explained in the video, finally I got my build. But again it has the same issue, not supporting unicode61 tokenizer. I tried several builds and all these time I build with DSQLITE_ENABLE_FTS4_UNICODE61=1 and other flags I mentioned below.

      After several attempt with so many permutations and combinations, I got it working. Tim’s video is a very good reference for building SQLite for WinRT. But if you want unicode61 support then follow the below steps, it’s same as Tim’s explained with some exclusion.

      1. mkdir c:\sqlite
      2. cd sqlite
      3. fossil clone http://www.sqlite.org/cgi/src sqlite3.fossil
      4. fossil open sqlite3.fossil
      5. fossil checkout winrt, never issue this command, it will never include unicode61
      6. Added this step to enable unicode61 tokenizer. Append the below config to Makefile.msc, you can see some config already existing append the below config to it.

        OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1

        OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1

        OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4_UNICODE61=1

      7. Compile the code by issuing nmake -f Makefile.msc sqlite3.dll FOR_WINRT=1

       

      I could build X86 and X64 using VS2012 command prompt for X86 and X64. But when I tried to compile for ARM I was getting some errors, I was fortunate enough to find a solution in StackOverflow. Followed that solution and I got the SQLite builds for X86, X64 and ARM.

      I don’t want to spend time in creating a vsix package and install it in my machine, instead I took the backup of SQLite for WinRT version 3.8.5, in my machine the installed path is C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1\ExtensionSDKs\SQLite.WinRT81. Then went into each folder and replaced the lib and sqlite dll with the respective builds I created.

      Leave your comments if you have any questions.

       

      Happy coding…

      Written by Sony Arouje

      July 17, 2014 at 6:06 pm

      Posted in .NET, WinRT

      Tagged with , , , , , ,

      WinRT TextBlock with HyperLinks

      with 5 comments

      I was doing some experiments with Window 8 app development. I wanted to show the text in a TextBlock with any URL as a clickable hyperlink, so that user can click on it and navigate to that webpage. We can do this easily via xaml as shown below. I googled a lot to find a way to do the same in MVVM approach. With no solution in hand I decided to come up with a solution using Attached Properties.

      <TextBlock x:Name="textValue" TextWrapping="Wrap">
           <TextBlock.Inlines>
               <Run Text="This is an example of how Hyperlink can be used in a paragraph of text.
                     It might be helpful for you look to"></Run>
               <Hyperlink NavigateUri="www.bing.com">bing</Hyperlink>
               <Run Text="for more answers in the future."></Run>
            </TextBlock.Inlines>
      </TextBlock>

       

      I am using Caliburn Micro to bind the text, so the above approach will not suit my requirement. The solution I come up with is Custom Attached Properties. In the Attached properties I applied the above logic but via code. Have a look at the code.

      using System;
      using System.Text;
      using Windows.UI.Xaml;
      using Windows.UI.Xaml.Controls;
      using Windows.UI.Xaml.Documents;
      
      namespace Test.App.AttachedProps
      {
          public class HyperLinkedTextBlock
          {
              public static string GetText(TextBlock element)
              {
                  if (element != null)
                      return element.GetValue(ArticleContentProperty) as string;
                  return string.Empty;
              }
      
              public static void SetText(TextBlock element, string value)
              {
                  if (element != null)
                      element.SetValue(ArticleContentProperty, value);
              }
      
              public static readonly DependencyProperty ArticleContentProperty =
                  DependencyProperty.RegisterAttached(
                      "Text",
                      typeof(string),
                      typeof(HyperLinkedTextBlock),
                      new PropertyMetadata(null, OnInlineListPropertyChanged));
      
              private static void OnInlineListPropertyChanged(DependencyObject obj, 
                   DependencyPropertyChangedEventArgs e)
              {
                  var tb = obj as TextBlock;
                  if (tb == null)
                      return;
                  string text = e.NewValue as string;
                  tb.Inlines.Clear();
      
                  if (text.ToLower().Contains("http:") || text.ToLower().Contains("www."))
                      AddInlineControls(tb, SplitSpace(text));
                  else
                      tb.Inlines.Add(GetRunControl(text));
              }
      
              private static void AddInlineControls(TextBlock textBlock, string[] splittedString)
              {
                  for (int i = 0; i < splittedString.Length; i++)
                  {
                      string tmp = splittedString[i];
                      if (tmp.ToLower().StartsWith("http:") || tmp.ToLower().StartsWith("www."))
                          textBlock.Inlines.Add(GetHyperLink(tmp));
                      else
                          textBlock.Inlines.Add(GetRunControl(tmp));
                  }
              }
      
              private static Hyperlink GetHyperLink(string uri)
              {
                  if (uri.ToLower().StartsWith("www."))
                      uri = "http://" + uri;
      
                  Hyperlink hyper = new Hyperlink();
                  hyper.NavigateUri = new Uri(uri);
                  hyper.Inlines.Add(GetRunControl(uri));
                  return hyper;
              }
      
              private static Run GetRunControl(string text)
              {
                  Run run = new Run();
                  run.Text = text + " ";
                  return run;
              }
      
              private static string[] SplitSpace(string val)
              {
                  string[] splittedVal = val.Split(new string[] {" "}, StringSplitOptions.None);
                  return splittedVal;
              }
          }
      }

       

      In the above code I analyze the text for urls after splitting it, you can also do it using RegEx. As this code is just for protyping, I didn’t pay much attention to the quality of it.

      In the xaml page I refer this attached property as shown below.

      xmlns:conv="using:Test.App.AttachedProps"

       

      In the Textblock, bind the text via the attached property as shown below.

      <TextBlock conv:HyperLinkedTextBlock.Text="{Binding TextVal}"/>

       

      If the TextVal has any words that starts with ‘http:’ or ‘www.’ then the above Custom Attached Property will create a HyperLink other wise create a Run control and add it to the Inline collection of the TextBlock.

       

      Happy coding…

      Written by Sony Arouje

      July 16, 2014 at 2:45 pm

      %d bloggers like this: