Sony Arouje

a programmer's log

Slack App to track our expenses hosted in a Raspberry Pi

leave a comment »

At 4Mans Land we keep struggling to track our expenses. We normally note the expenses in Whatsapp and later move to a shared excel sheet. But this is always have difficulties, there will be lot of noises in the whatsapp with ongoing discussions. We also use slack for discussions, so I decided to integrate an expense app and evaluated some. Most of them are paid and don’t want to pay for an app at this stage. One night decided to write an app for slack and by morning finished the basic app that can store expenses in a mongodb. This whole experiment started as a fun to play with some thing new and also understand the slack api.

Wrote the server in nodejs and choose mongo db for persistence. For testing the slack integration, I used ngrok to create a local tunnel. also evaluated localtunnel.me which is a free version, but very unstable. ngrok is good but we have to pay $5 per month for license.  Started evaluating other alternatives to host my server, heroku was another alternative and used it several times earlier. At the moment we wanted to spend less for hosting and infrastructure. At last decided to host the server at my home, I have a really good stable internet connection with more than 80mbps speed and a Gigabit router. Added a port forwarding at my router,  expected to access the port immediately but to my surprise it’s not working. Done port forwarding so many times earlier and could access stuffs inside my network without any issues, my ISP was different that time. Then called up my ISP support, they informed me that without a static ip I wont be able to do port forwarding, for static IP I have to pay a very minimal fee and is life long unless I switch the provider. Paid the amount and in 2 days got my static IP and could do port forwarding successfully. Also set up dynamic dns at noip.com to give a good name to my IP. With all these settings done, changed the url in slack app and used the one I setup at noip.com. Run the nodejs server at my dev machine and fired a command from slack app, viola received the command to the server running in my laptop. The server is ready and is running in my laptop, but required a system which could run 24/7. The cheap option came to my mind was to host the nodejs server in one of the Raspberrypi lying in my table, one night I decided to setup the pi with the latest Raspbian stretch.

Setting up the Raspberry pi

Expected to finish the whole setup in less than an hour, as did this several times earlier but not that day. After installing the stretch, apt-get update started throwing hash sum error, reinstalled the os couple of times. Same error again and again. This error sent me for a wild goose chase, reading one forum after another and tried all the suggestions but nothing changed. At last came across this stackoverflow post which fixed the issue and could update the os, phew.

Next installing the nodejs, used nodejs version maintained here and issue the ubuntu command, for e.g. to install nodejs 10 issue the below command from your raspberry pi

curl sL https://deb.nodesource.com/setup_10.x | sudo -E bash – sudo aptget install y nodejs

Next task is installing Mongodb, apt-get install mongodb installed an earlier version of mongodb and is not suitable for the mongoose orm which I am using in the code, either I have to use an older version of mongoose or try to find a way to install a new version of Mongodb. I choose the later and try hunting for some clues to install some newer version of mongodb. At the end, come accross this post, which has all the details of installing mongodb in Rpi jessie, which is good enough in stretch as well, also he provided a link for stretch mongo binaries. Followed the instructions and at the end mongodb started running in my machine.

When I try to connect from Compass to rpi’s mongodb instance, it’s not getting connected. Reading through some docs and forums realized that I have to comment bind_ip in /etc/mongodb.conf, commented out that config and able to connect from compass.

Before going to bed at 2am, copied the nodejs code to rpi, did some testing and all went well. Could post expenses from slack to the service running in my pi. Went to bed with peace of mind.

What this app does?

The main focus of this app is to capture the expense, for now it uses slack command to forward text to the service. Initially created a strict pattern to record expense for e.g.

/expense spent 4000 INR on Jill to fetch a pail of water by Jack

Here spent should be first word followed by amount, after ‘on’ specify the description and after ‘by’ specified who paid the amount. The nodejs service will parse them and place them in separate fields in mongodb collection. Then to query the expense, some thing like

/expense query date today

/expense query date 05/12/2018 – 05/14/2018

So here ‘spent’ and ‘query’ is a keyword, based on this keyword different handling logics will kicks in and complete the task.

I felt the syntax is more restrictive, started analyzing options to process the sentence more naturally. I come across natural, a NLP library for nodejs. Using natural’s BayesClassifier trained the system to categorize the input text and derive the right keyword, which again calls the different logic and get the task done. After the classification training, the system can take inputs like

/expense Jack paid 4000 by Card for ‘Jill to fetch a pail of water’ on 05/16/2018

The above code will classified as spent, then added some code to extract relevant part from the text. Not pure NLP approach, any thing inside single quotes will be considered as expense. Any date in the text is considered as the payment date and so on. I am learning NLP, in future I might achieve a better translation of text.

Querying command is modified as shown below

/expense today

/expense between 05/12/2018 – 05/14/2018

Can also query and return expenses in csv format

/expense today csv  will return the expense in comma seperated format.

Slack output

image

After each expense created successfully, it returns the expense with the ID and the actual text we passed to the expense command. For e.g to create first expense passed the text like

/expense Jack paid 4000 to ‘Jill to fetch a pail of water’

Here is the output for querying todays expense, issue a command like

/expense today

image

 

In csv format (/expense today csv)

image

We can also delete an expense, only the expense you created can be deleted.

/expense delete today: delete all the expense you entered today

/expense delete 116: delete the expense with id 116

Had a great fun during this experiment and learned few things.

Happy coding…

Advertisements

Written by Sony Arouje

May 18, 2018 at 5:17 pm

react, redux and cycle – Introduction

leave a comment »

Last couple of months we were working mostly in react js to develop a flexible platform for one of the product we are working. I am planning to make a couple of post to explain how to start developing in react with redux and cycle. To setup my dev environment, I used the react boilerplate created by my friend Sendhil. This is a basic template to jumbstart react js development with linting.

I am not going in depth of redux or redux-cycle, it’s just an attempt to help setup the initial phase of the development. If you are not familiar with redux or why we need redux, better learn it from the creator.

Let’s use the template and incrementally add more features to it. I created a new github repository with some initial code to start with.

Below are the new npm dependencies added to package.json

  • react-redux: "^5.0.4",
  • redux: "^3.6.0",
  • @cycle/http: "^13.3.0",
  • @cycle/run: "^3.1.0",
  • @cycle/time: "^0.8.0",
  • redux-cycles: "^0.4.1",
  • xstream: "^10.9.0",
  • prop-types: "^15.5.10"

For any redux application we need to setup a store. I created a store as well, see the code below.

import { applyMiddleware, createStore, compose } from 'redux'; import { createCycleMiddleware } from 'redux-cycles'; import { run } from '@cycle/run'; import { makeHTTPDriver } from '@cycle/http'; import { timeDriver } from '@cycle/time'; import logger from 'redux-logger'; // combined all the reducers in the application import reducers from './reducers'; // combined all the cycles in the application import cycles from './cycles'; //create cycle middleware to attach to redux store. const cycleMiddleware = createCycleMiddleware(); const { makeActionDriver, makeStateDriver } = cycleMiddleware; //we might use multiple middleware, here we used a logger //and cycle. We can add more middleware by adding them to //the below array. const middleWare = [ logger, cycleMiddleware, ]; const initState = {}; // more about compose here http://redux.js.org/docs/api/compose.html let composeEnhancers = compose; // adding redux dev tool to visualize the store state. // should be enabled only in development. if (process.env.NODE_ENV !== 'production') { const composeWithDevToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; if (typeof composeWithDevToolsExtension === 'function') { composeEnhancers = composeWithDevToolsExtension; } } const store = createStore( reducers, // all the available reducers combined initState, // initial state of the reducers composeEnhancers( // adding store enchancers applyMiddleware(...middleWare), // attaching the middleware ), ); // calling cycle's run() we are activating the cycles that we created // here all the different cycles are combined to one. run(cycles, { ACTION: makeActionDriver(), STATE: makeStateDriver(), Time: timeDriver, HTTP: makeHTTPDriver(), }); export default store;

 

Added some inline comments to the code and hopefully it’s pretty self explanatory. Once we have the store created, we need to pass down the store to other components, so that they can access state or dispatch actions.

Let’s edit index.jsx and add the below code.

import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import store from './store/create-store'; import App from './App'; render( <Provider store={store}> <App /> </Provider> , document.getElementById('root'));

 

Great, we created a basic react app with redux. In next post I will cover how to create reducer and handle side effects using redux-cycle.

 

Happy coding…

Written by Sony Arouje

September 22, 2017 at 6:32 pm

Posted in JavaScript, React

Tagged with , ,

RF Communication using nrf24L01 and Nodejs addon

leave a comment »

Recently I started experimenting with radio communication with low cost nrf24L01 modules. These modules are very cheap compare to XBee modules which I used earlier. With these nrf24 modules we could enable wireless communication between Arduinos and Raspberry pi very effectively and economically. For my experiment I used two nrf24 modules, one connected to an Arduino Uno and another to a Raspberry pi 1.  Here is the pin connection details

Seq NRF24L01 RPi Arduino Uno
1 GND 25 (GND) GND
2 VCC 17 (3.3v) 3.3v
3 CE 15 7
4 CSN 24 8
5 SCK 23 13
6 MOSI 19 11
7 MISO 21 12
8 IRQ

 

For testing the communication, I used the RF24Network library, which is very good and has good documentation. Also it comes with e.g for both Arduino and RPi. So I didn’t write any single code just used the e.g and able to see the communication working, initially I had some troubles and at the end every thing worked well, I can see the data coming from Arduino in RPi. 

My intention is to use these modules in RPi and write code in nodejs. Unfortunately there is no nodejs support for this library. So last night I decided to write a nodejs addon for this C/C++ library. I didn’t had any experience in writing a nodejs addon, I spend an hour understanding the Nan and creating very simple addons. Then I started writing the addon for RF24Network, this task was very hard than trying with simple hello world addons.

Node-gyp was keep on failing when it tries to compile the RFNetwork modules. In my searches I realized that node-gyp uses make utility and I need to add the C/C++ files of this library. At the end I could compile the node addon. See the binding.gyp file

{ "targets": [ { "target_name": "nrf24Node", "sources": [ "nrf24Node.cc", "RF24/RF24.cpp", "RF24/utility/RPi/spi.cpp", "RF24/utility/RPi/bcm2835.c", "RF24/utility/RPi/interrupt.cpp", "RF24Network/RF24Network.cpp", "RF24Network/Sync.cpp" ], "include_dirs": [ "<!(node -e \"require('nan')\")", "RF24Network", "RF24" ], "link_settings": { "libraries": [ "-RF24", "-RFNetwork" ] } } ] }

 

I should say, I am just a beginner in node-gyp and this binding.gyp might need some improvements. Anyway with this gyp file, the compilation succeeded.

Next is to create the addon file. Here I had to learn more about the data types of Nan and Callbacks. I started simple functions to begin with and compile again, then moved on to next. I took more time in understanding callbacks which allows the addon to call javascript callback functions. Also spend a lot of time in understanding threading and creating a module to continuous listening of incoming messages and trigger the callback function, so that nodejs can process those incoming messages. I use libuv for threading, it seems more easy to understand than Async worker modules in Nan.

That whole night I spend learning and writing and refactoring the addon, I finished the module by early morning. By that time I could write a nodejs app and could listen to incoming messages.

Here is the sample code in node js to listen and acknowledge the message back to the sender.

var rf24 = require('./build/Release/nrf24Node.node'); rf24.begin(90,00); rf24.printDetails(); rf24.write(1,"Ack"); rf24.readAsync(function(from, data){ console.log(from); console.log(data); rf24.write(from,"Ack"); }); process.on('SIGINT', exitHandler); function exitHandler() { process.exit(); rf24.close(); }

 

Here is the complete addon. The code is uploaded to github, with the steps to compile and use it your own nodejs applications.

#include <nan.h> #include <v8.h> #include <RF24.h> #include <RF24Network.h> #include <iostream> #include <ctime> #include <stdio.h> #include <time.h> #include <string> using namespace Nan; using namespace v8; RF24 radio(RPI_V2_GPIO_P1_15, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ); RF24Network network(radio); Nan::Callback *cbPeriodic; uv_async_t* async; struct payload_t { // Structure of our payload char msg[24]; }; struct payload_pi { uint16_t fromNode; char msg[24]; }; //-------------------------------------------------------------------------- //Below functions are just replica of RF24Network functions. //No need to use these functions in you app. NAN_METHOD(BeginRadio) { radio.begin(); } NAN_METHOD(BeginNetwork){ uint16_t channel = info[0]->Uint32Value(); uint16_t thisNode = info[0]->Uint32Value(); network.begin(channel,thisNode); } NAN_METHOD(Update) { network.update(); } NAN_METHOD(Available) { v8::Local<v8::Boolean> status = Nan::New(network.available()); info.GetReturnValue().Set(status); } NAN_METHOD(Read) { payload_t payload; RF24NetworkHeader header; network.read(header,&payload,sizeof(payload)); info.GetReturnValue().Set(Nan::New(payload.msg).ToLocalChecked()); } //-------------------------------------------------------------------------------- NAN_METHOD(Begin){ if (info.Length() < 2) return Nan::ThrowTypeError("Should pass Channel and Node id"); uint16_t channel = info[0]->Uint32Value(); uint16_t thisNode = info[1]->Uint32Value(); radio.begin(); delay(5); network.begin(channel, thisNode); } NAN_METHOD(Write){ if (info.Length() < 2) return Nan::ThrowTypeError("Should pass Receiver Node Id and Message"); uint16_t otherNode = info[0]->Uint32Value(); v8::String::Utf8Value message(info[1]->ToString()); std::string msg = std::string(*message); payload_t payload; strncpy(payload.msg, msg.c_str(),24); RF24NetworkHeader header(otherNode); bool ok = network.write(header,&payload, sizeof(payload)); info.GetReturnValue().Set(ok); } void keepListen(void *arg) { while(1) { network.update(); while (network.available()) { RF24NetworkHeader header; payload_t payload; network.read(header,&payload,sizeof(payload)); payload_pi localPayload; localPayload.fromNode = header.from_node; strncpy(localPayload.msg, payload.msg, 24); async->data = (void *) &localPayload; uv_async_send(async); } delay(2000); } } void doCallback(uv_async_t *handle){ payload_pi* p = (struct payload_pi*)handle->data; v8::Handle<v8::Value> argv[2] = { Nan::New(p->fromNode), Nan::New(p->msg).ToLocalChecked() }; cbPeriodic->Call(2, argv); } NAN_METHOD(ReadAsync){ if (info.Length() <= 0) return Nan::ThrowTypeError("Should pass a callback function"); if (info.Length() > 0 && !info[0]->IsFunction()) return Nan::ThrowTypeError("Provided callback must be a function"); cbPeriodic = new Nan::Callback(info[0].As<Function>()); async = (uv_async_t*)malloc(sizeof(uv_async_t)); uv_async_init(uv_default_loop(), async, doCallback); uv_thread_t id; uv_thread_create(&id, keepListen, NULL); uv_run(uv_default_loop(), UV_RUN_DEFAULT); } NAN_METHOD(PrintDetails) { radio.printDetails(); } NAN_METHOD(Close){ uv_close((uv_handle_t*) &async, NULL); } NAN_MODULE_INIT(Init){ Nan::Set(target, New<String>("beginRadio").ToLocalChecked(), GetFunction(New<FunctionTemplate>(BeginRadio)).ToLocalChecked()); Nan::Set(target, New<String>("beginNetwork").ToLocalChecked(), GetFunction(New<FunctionTemplate>(BeginNetwork)).ToLocalChecked()); Nan::Set(target, New<String>("update").ToLocalChecked(), GetFunction(New<FunctionTemplate>(Update)).ToLocalChecked()); Nan::Set(target, New<String>("printDetails").ToLocalChecked(), GetFunction(New<FunctionTemplate>(PrintDetails)).ToLocalChecked()); Nan::Set(target, New<String>("available").ToLocalChecked(), GetFunction(New<FunctionTemplate>(Available)).ToLocalChecked()); Nan::Set(target, New<String>("read").ToLocalChecked(), GetFunction(New<FunctionTemplate>(Read)).ToLocalChecked()); Nan::Set(target, New<String>("readAsync").ToLocalChecked(), GetFunction(New<FunctionTemplate>(ReadAsync)).ToLocalChecked()); Nan::Set(target, New<String>("write").ToLocalChecked(), GetFunction(New<FunctionTemplate>(Write)).ToLocalChecked()); Nan::Set(target, New<String>("close").ToLocalChecked(), GetFunction(New<FunctionTemplate>(Close)).ToLocalChecked()); Nan::Set(target, New<String>("begin").ToLocalChecked(), GetFunction(New<FunctionTemplate>(Begin)).ToLocalChecked()); } NODE_MODULE(nrf24Node, Init)

All the credit goes to the developers of RF24 and RF24Network library, I just created an addon for the great library. Along the way I learned a lot and could finish the nodejs addon.

 

Happy coding…

Written by Sony Arouje

February 5, 2017 at 4:57 pm

My Experience in E-Vaping

with 3 comments

I was a smoker for so many years. I tried so many ways to quit this habit, at one point I tried Nicotine gums but ended up chewing nicotine gums and smoking at same time. Recently I went to England for a business trip and one of my colleague there quit smoking and moved to E-Cigarette or E-Vaping. I thought, I should give a try but I wasn’t sure I can quit smoking. The hotel where I stayed, I met another guy with an E-Vaping device and when talking to him, he said he quit smoking a year ago with the help of this device. That night I decided, I should buy one and ordered one from Amazon. I didn’t spend much time in understanding the technical details of these devices in detail. So I ordered a beginner model named Thorvap, which cost me around 24 GBP, not a big deal, also bought some E-Liquids. After I came back to India, I started using this device, and for last two weeks I haven’t touched a cigarette.

I bought the below device

Image result for thorvap 30w

 

I didn’t regret buying this device. In my spare time I started researching more about E-Vaping and accessories attached to it. If this post inspire you to buy one then spend some time in understanding different types of systems available in the market before buying one.

What is an E-Vaping device

Any E-Vaping device produce vapor from a liquid by heating a coil. This liquid is a mix of Propylene Glycol, Vegetable Glycerin, Some Flavor and some percentage of Nicotine. Once you moved out of Cigarette, you can reduce the percentage of Nicotine and later can use liquids with zero nicotine. Devices comes in several variations like 30, 60 or 120 watts, as per my understanding this will tell how heat the coil can produce and thus increase the vape production.

Parts in E-Vaping device

There are mainly three parts

  1. Mod
  2. Tank
  3. Atomizer

Mod: This part contains the battery and the temperature controlling system. It’s not very complicated to use it, it has an on/off button and buttons to increase or decrease the temperature.

Tank: This is the top part with the glass. Liquid get filled in this tank. Tanks come is different sizes like 3ml, 6ml etc.

Atomizer: This is a very crucial part to be decided before buying one. In simple terms, any atomizer contains a coil, cotton and a screw terminal screwed to the battery.

There are two major type of atomizers

  • RBA (Rebuildable Atomizers)
  • Non RBA

The coils and cotton will get deteriorate after some weeks, again it depends on how you vape and the sweet content of the liquid. There are so many factors that affects the life span of these coils and cotton.

In Non RBA’s, you have to buy these part and is a costly affair. I bought a pack of 5 for 11GBP. Some says, these can be reused by washing in hot water or vodaka, I haven’t tried this personally. As per my understanding vaping with Non RBAs add costs.

RBAs have rebuildable coils, that means we can unscrew it and change the coil and cotton. These coils can be easily made by ourselves. Should be careful to maintain the desired ohm of the coil, otherwise you might damage the mod. Check youtube and can see a lot of videos about how to do it, and learn more about how to maintain the ohm of the coil. RBAs are again divided into RDA and RTA.

RDA (Rebuildable Drip Atomizer), in this system there is no tank to hold the liquid. We need to wet the cotton with liquid, personally I don’t like it, as I might ended up carrying liquid where ever I go. In RTA (Rebuildable Tank Atomizer) system, the liquid can be filled in a tank. The tank capacity comes in different variations like 3ml, 6ml etc.

After learning more about the system, I decided to buy a second device. I think a second device is always useful, in case my existing one stop working. I ordered for SMOK XCube Mini and TFV8 Baby Tank and a separate RBA Atomizer.

What Next?

Buy an e-Vaping device and give it a try. Just like me, you might quit smoking. After two weeks, I can see a lot of difference in my body. Earlier I used to struggle to breath after running for a kilometer and now I feel more comfortable running a km. I think after some time I can reduce the nicotine in the liquid and later I can stop vapping all together.

Still research is going on whether e-Vaping is healthy but it’s much less harmful than normal cigarette.

Note: If you are residing in Karnataka, then selling of E-Cigarette and liquids are banned. I feel it’s a strange decision by the government. May be you can ship it to near by state and get it through some friends. There is a will there is a way.

Written by Sony Arouje

December 9, 2016 at 1:08 am

Posted in Misc

Tagged with ,

Program ESP8266 with Arduino IDE

with 4 comments

Last couple of days I was trying to setup an ESP8266 module to program using Arduino environment. By Default ESP8266 bootloaded with AT Bootloader. Initially I connected ESP to Arduino and communicated using AT Mode via WiFiESP library.

The intention of my experiments is to add internet support in my Aeroponic controller. But AT mode deals with strings and thus increase the flash size, and when I added MQTT functionality with rest of Aeroponic sketch, I almost filled the flash size of Atmega328. So I decided to look for alternative options.

One of the beauty of ESP8266 is, it has it’s own flash memory. Also the integration with Arduino IDE. This way I can write Arduino sketch and embed it into ESP8266 instead of writing it to Atmega328.

Installing ESP8266 addon to Arduino IDE.

Sparkfun have a nice post about setting up the IDE. At the end of tutorial they choose ‘Sparkfun ESP8266 Thing’, instead I selected ‘Generic Esp8266 Module’, see the screen shot below.

 esp_arduino_ide

Hardware Connection

To write Arduino sketches to ESP we need a USB TTL module. Connect the module as below.

  • ESP8266-> USB TTL
  • GND-> GND
  • TX-> RX
  • RX-> TX
  • GPIO0-> GND

I powered the ESP module from an external source, ESPs are really power hungry, I am not sure whether the USB module can give the required current.

  • ESP8266-> External power
  • VCC-> 3.3v
  • CH_PD->3.3v

Make sure you have a  common GND, for ESP, External power and USB TTL. That means connect all GNDs together. If there is no common GND then expect the unexpected, IDE will keep throwing fatal exception.

Once the sketch is uploaded, connect GPIO0 to VCC, then switch off/on the ESP module. Now the ESP will start running the sketch.

Challenges

Keep getting wdt reset message as shown below. To test I added the blink demo with a serial write. This simple program works well until I add ‘ESP8266WiFi.h’, after this header file and uploading the sketch will start throwing the below in Serial monitor.

ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
v09f0c112
~ld

I tried a lot of options to resolve this issue. First I thought the module is not receiving enough current, so I powered it with 5v. This doesn’t make any difference.

In one of ESP forums some one suggest to erase flash using ESPTool, so I setup ESPTool and issued command like

python esptool.py p com6 erase_flash

This didn’t work out either. In another forum one person suggest to write blank.bin to 0x7E000, also mentioned that some times the reset can occur because of corrupted flash. This leads me to believe that corrupted flash causing the reset. So I decided to start all over again.

As an initial step I decided to boot with default AT bootloader. Here is a great post to follow.

While trying to bootload, esptool crashes always with ‘fatal exception’. I changed my USB Serial and tried again, this time all the bootloading steps works and configured the ESP back to AT mode. Then again I tried to burn the arduino sketch via Arduino IDE and it worked really well.

So I believe the wdt reset caused by, an issue with USB Serial module or corrupted flash. Now ESP8266 is working fine without any reset.

Written by Sony Arouje

November 7, 2016 at 11:40 pm

Posted in Arduino

Tagged with

Aeroponic Controller V4

with 3 comments

After the successful completion of my Aeroponic Contoller V3. I started designing the next version of the PCB. This time I decided to package every thing in a single board. In V3, controller depends on external relay modules to on/off devices. In the new version Relays are inbuilt. One of the major change in the new version is, the system is controlled by a bare bone Arduino using Atmega328. The new board has all the features of V3 plus some new features.

The board has several debugging features which allow me to monitor the internal activity of the system via a serial monitor. The board also has the ability to communicate to an external Arduino via I2C, this feature is very essential in case of testing and bug fixing.

V4 Controller with inbuilt Relay modules

IMG_1642

 

IMG_1644

 

V3 Controller with external relay modules

The below system is currently operational at my home. As you can see the system uses 4 external relay modules.

IMG_1255 - Copy

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.

pH Feeder: This is a new feature, it’s very similar to Nutrient feeder. Instead of adding nutrients this feeder adds pH modifier like Phosphoric acid or similar modifiers to correct the pH level of the water.

Real Time Clock: To deal with time critical logics.

WiFi Module: Allow the system to communicate with Internet, this allow me to control the system from any where in the world.

Communication with the Controller: I am reusing the Android application I wrote for V3. As of now the system talks via Bluetooth.

Written by Sony Arouje

October 6, 2016 at 2:33 am

Posted in Arduino

Tagged with ,

Some experiments in Cyanotype Photographic printing

leave a comment »

Last week I got interested in Cyanotype photographic printing and started investigating about the chemistry and the whole process of doing it. It’s real fun and cheap way of printing photographs. In short Cyanotype printing involves sensitizing Paper/wood/cloth/glass with some chemicals and expose it to UV radiation/Sun light with a negative film covering the print area.

There are hundreds of tutorial talking about the whole process, here I merely repeating the process again. In Cyanotype process two major components are the sensitizing chemical and the paper. Let’s talk about the steps in Cyanotype.

Sensitizing Chemistry

I followed the old Cyanotype process. The two chemicals I need for that is

  • Ammonium Ferric Citrate
  • Potassium Ferricyanide

Most of the tutorials of Cyanotype process talks about Ammonium Ferric Citrate (Green), I couldn’t find Green version instead I used the brown one.

These two chemicals comes as powder, so need to mix it to create A and B solution.

  • Solution A: 100 ml water and 25g Ammonium Ferric Citrate mixed together.
  • Solution B: 100 ml water and 10g Potassium Ferricyanide mixed together.

Note: some sources says, use distilled water, I used the normal filter water for mixing.

Both A and B should be kept in separate containers. This can be reused to create working solution. To create the working solution, take equal parts from two (A and B) solutions and then mix well.

 

Sensitizing the paper
Paper type is very important in Cyanotype process, I used different types of paper for this process. I got really good result from very cheap drawing paper sells at normal stationary shops, which cost around 8₹ for a large sheet and can cut 6 or more A4 sheets. I also tried with A4 paper which cost around 12₹ each and got a very dirty yellow look, which I didn’t like. I suggest start with cheap drawing paper.

Next we need to sensitize the paper with the working solution we created from the A and B solution. I used a normal paint brush and paint the solution to the paper. Make sure to use a moderate dark room. Keep the paper to dry in a dark place, I used my bookshelf to dry it completely. You can also use a hair dryer and can be used immediately, I don’t have a hair dryer instead I used a hot air gun in very mild temperature. The paper will turn yellow once it dried.

 

Printing or Exposing

I experimented with A4 size paper. To print photos, we need to create a negative of A4 size. To create the big negative I used a black and white photo and invert it in an image editing app. Then adjust the contrast to get a desired look for the negative. This negative should print on a transparent sheet, I bought couple of OHP sheet and print the negative using my laser printer.

Next we need to expose the sensitized paper with UV rays. I used an A4 size plywood and transparent plexi glass to keep the paper and negative in position. Here is good video showing the whole process.

Sun light is the best resource for UV rays. But I live in an apartment and I don’t get enough sunlight in my balcony. So I used a light source created for my Aeroponic system. My Light source is an array of 3W red and blue LEDs, which I sourced from Aliexpress and assembled by me and my father. Also this artificial UV source helped me to experiment at night as well. Below is my UV light source, it’s not very fancy, a DIY system. Important part is, it’s shock proof :).

IMG_1616

 

In normal sun light, we need to expose the paper for about 8-10mins, in my light source I need to expose for around 50mins. I experimented with different exposure time and came to 50mins as ideal.

Developing

Developing the paper is an easy process, just dip the exposed paper in water for 3 to 4 mins. My tap water is bit Alkaline, Cyanotype works well in Acidic water, so I put couple of drops of Phosphoric acid to water to make it acidic and wash for a minute then wash it in normal tap water for about 3 mins. The timing can only determined by trial and error, when you see the blue color is fading take the paper out and keep it for drying.

 

Some prints

1. Dirty yellow stained print, this caused by the paper type. This A4 sheet is around 12₹, but gives me a very bad output.

Cyanotype_stained

 

2. An over exposed print, highlight become mild blue. Under UV Light for around 2hrs

Cyanotype1

3. Reasonable good print, exposed for around 50mins.

Cyanotype2

 

All the above photos are scanned using a normal scanner not from a good photo scanner. Later I will post some photos from my photo scanner. The actual image looks a bit more bluish.

 

What next?

I need to spend some time experimenting the bleaching and tanning process. The whole process is real fun, need to experiment with different photos as well.

Written by Sony Arouje

September 16, 2016 at 9:45 pm

Posted in Misc

Tagged with

%d bloggers like this: