Skip to Content
Technical Articles

Controlling Smart Bulb with Blockchain

In this blog, we’ll learn and demonstrate how to control the smart bulb “Yeelight” with Blockchain from the SAPUI5 app. We will utilize the Hyperledger Fabric service in SAP Cloud Platform.

There are four major components that we need to build and configure:

  1. Chaincode (Smart Contract) Logic
  2. Hyperledger Fabric Configuration
  3. SAPUI5 App in SAP Web IDE
  4. NodeJS App: Subscriber

Chaincode (Smart Contract) Logic

Create the chaincode (known also as smart contract) written in Go language with an invoke contains the following logic:

  • The read function is defined to get the JSON object based on the key ID of the object
  • The write function is defined to create the object with argument ID and JSON object.
    An event “
    event-name” is attached to write function so it can immediately notify the subscriber (for this case is NodeJS app).
// Init is called during Instantiate transaction.
func (cc *SmartBulb) Init(stub shim.ChaincodeStubInterface) peer.Response {
	return Success(http.StatusNoContent, "OK", nil)
}

// Invoke is called to update or query the ledger in a proposal transaction.
func (cc *SmartBulb) Invoke(stub shim.ChaincodeStubInterface) peer.Response {

	function, args := stub.GetFunctionAndParameters()

	switch function {
	case "read":
		return read(stub, args)
	case "write":
		return write(stub, args)
	default:
		logger.Warningf("Invoke('%s') invalid!", function)
		return Error(http.StatusNotImplemented, "Invalid method! Valid methods are 'read|write'!")
	}
}

// Read text by ID
func read(stub shim.ChaincodeStubInterface, args []string) peer.Response {

	if len(args) != 1 {
		return Error(http.StatusBadRequest, "Parameter Mismatch")
	}
	id := strings.ToLower(args[0])

	if value, err := stub.GetState(id); err == nil && value != nil {
		return Success(http.StatusOK, "OK", value)
	}

	return Error(http.StatusNotFound, "Not Found")
}

// Write text by ID
func write(stub shim.ChaincodeStubInterface, args []string) peer.Response {

	if rc := Validate("create", args /*args[0]=id*/, "%s", 1, 64 /*args[1]=state*/, "%json", 2, 4096); rc.Status > 0 {
		return rc
	}
	
	if err := stub.SetEvent("event-name", []byte(args[1])); err != nil {
		return shim.Error(err.Error())
	} 

	if err := stub.PutState(args[0], []byte(args[1])); err == nil {
		return Success(http.StatusCreated, "Created", nil)
	} else {
		return Error(http.StatusInternalServerError, err.Error())
	}
}

We will deploy the chaincode into Hyperledger Fabric later on. The files and folder structure of Chaincode as follow:

The complete chaincode source code can be found here.

Hyperledger Fabric Configuration

Enable the Hyperledger Fabric Service on SAP Cloud Platform to use the service.

There are few steps we need to do on the Hyperledger Fabric Configuration:

  • Create Instance
  • Create Channel
  • Create Channel Service Instance
  • Install & Instantiate Chaincode
  • Test Chaincode
  • Verify Blocks

Create Instance

  • Navigate to Service: Hyperledger Fabric – Overview and select Instances.
  • Select New Instance.
  • Choose service plan dev. Just ignore the warning message and click Next.
  • Select Next.
  • Select application: (None) and select Next.
  • Enter instance name BulbBlockchain and select Finish.
  • Now we should see the new instance BulbBlockchain that was just created. Select Open Dashboard.

Create Channel

  • From the Dashboard menu, select Channels.
  • Select Create Channel.
  • Enter channel name bulbchannel and select Create.
  • bulbchannel is created.

Create Channel Service Instance

  • Select Create Channel Service Instance in the same Space.
  • Select Create.
  • Service instance BulbBlockchain.bulbchannel is created.

Install and Instantiate Chaincode

  • Select Open Channel Service Instance Dashboard.
  • Select Chaincode.
  • Package the chaincode into smartbulb.zip and install and instantiate.
  • Select Install Chaincode and choose file smartbulb.zip.
  • Select Install Chaincode.
  • The chaincode successfully installed.

Test Chaincode

  • Navigate back to Chaincode, select chaincode smartbulb that we have installed.  Then select Test Chaincode.
  • We have two methods:
    Get: to read the JSON value from the Blockchain.
    Post: To submit the JSON value to the Blockchain.Select Authorize.
  • Select Post method and submit the following information to the Blockchain.
    id: 1
    object:

    {
        "light_status": "true",
        "RGB": "3,252,240"
    }​

    If there is no error, you will get the response 200 – Created.

  • Write down the authorization header information, we will use this information in SAPUI5 app later on.
    authorization: Bearer eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vcDUyODAzNHRyaWFsLmF1dGhlbnRpY2F0aW9uLmV1MTAuaGFuYS5vbmRlbWFuZC5jb20vdG9rZW5fa2V5cyIsImtpZCI6ImtleS1pZC0xIiwidHlwIjoiSldUIn0.eyJqdGkiOiJhNzc2NjY5NTIxZmI0Y2Y5OTU5NDM0MzE0N2E3ZjMwNiIsImV4dF9hdHRyIjp7ImVuaGFuY2VyIjoiWFNVQUEiLCJ6ZG4iOiJwNTI4MDM0dHJpYWwiLCJzZXJ2aWNlaW5zdGFuY2VpZCI6IjkwNzhmYTM3LThmZDQtNGI3Ni1iMDFjLTc5MWZlZDQ4ZDZkMSJ9LCJzdWIiOiJzYi05MDc4ZmEzNy04ZmQ0LTRiNzYtYjAxYy03OTFmZWQ0OGQ2ZDEhYjEwMjYyfG5hLTQyMGFkZmM5LWY5NmUtNDA5MC1hNjUwLTAzODY5ODhiNjdlMCFiMTgzNiIsImF1dGhvcml0aWVzIjpbInVhYS5yZXNvdXJjZSJdLCJzY29wZSI6WyJ1YWEucmVzb3VyY2UiXSwiY2xpZW50X2lkIjoic2ItOTA3OGZhMzctOGZkNC00Yjc2LWIwMWMtNzkxZmVkNDhkNmQxIWIxMDI2MnxuYS00MjBhZGZjOS1mOTZlLTQwOTAtYTY1MC0wMzg2OTg4YjY3ZTAhYjE4MzYiLCJjaWQiOiJzYi05MDc4ZmEzNy04ZmQ0LTRiNzYtYjAxYy03OTFmZWQ0OGQ2ZDEhYjEwMjYyfG5hLTQyMGFkZmM5LWY5NmUtNDA5MC1hNjUwLTAzODY5ODhiNjdlMCFiMTgzNiIsImF6cCI6InNiLTkwNzhmYTM3LThmZDQtNGI3Ni1iMDFjLTc5MWZlZDQ4ZDZkMSFiMTAyNjJ8bmEtNDIwYWRmYzktZjk2ZS00MDkwLWE2NTAtMDM4Njk4OGI2N2UwIWIxODM2IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInJldl9zaWciOiIyOWMwZmVhZCIsImlhdCI6MTU1MzY5MTU2NCwiZXhwIjoxNTUzNzM0NzY0LCJpc3MiOiJodHRwOi8vcDUyODAzNHRyaWFsLmxvY2FsaG9zdDo4MDgwL3VhYS9vYXV0aC90b2tlbiIsInppZCI6ImQ4MGY5YTYzLWFjZmItNDhhMC04ODkxLWI0MTA5YTEwMzkxMiIsImF1ZCI6WyJzYi05MDc4ZmEzNy04ZmQ0LTRiNzYtYjAxYy03OTFmZWQ0OGQ2ZDEhYjEwMjYyfG5hLTQyMGFkZmM5LWY5NmUtNDA5MC1hNjUwLTAzODY5ODhiNjdlMCFiMTgzNiIsInVhYSJdfQ.TjCwvUwT1qJ2DEGB8RhjiHRUrAzXrGAk_U7cejoFEesu5UTfctwLcVmybADZF4Zxfx4NpE52O_E5pTTQMdo6icH60PfhnDcCfebEMzZRUeJ35fsWe8y_lLadmqatS1MWUTMK_eB_f_wjz9ezOmR3giV0CZBwNW64uz1bhJipePIKfFiEcn5kYYCDvq7j3yBPmLcSMJ37QnlF3oISo3MH-2LDKg87bMVi5K0lCPIlYRjvKfNjH_nnaDK2XjddYpQYWZXzsNcMwewA18plte8Fmyd82iCBjJ-w4CgQe6P1X6V4RKkKkN5iKolx5Imk7YPYyGdAk-N6VG23W5UbFiLUEDyL-Pvg8QmWtiOZ3pqX_Eh13SCI-JTnH9TRAfQJWMN8P_KanRi-JMmDT6MYd5ocuMTZpUUBxUUttthR2v_hGNduWOWiUEw1OFFgJoamSJNdgQvUtl9QMrFltZQn7NLtsSXWg_SqSC80eAsy2E541rJMOAysFgKNoCfk6Fdfe8icXFq9wRFjRkTl1jVcS9zNr0gxsaPJ67SJix8_gJLSA7uU4TrykxZbz1KbzZIhaqsWVCfzmx0tBaJiCcWhQAmOVnibNDCG-37VuKNxRldjB8CO2zlCh2JDT1cn0SLzGh6uU4fUDYU4bBm0FR4ljIJJrZ_XpI5FB0RVDJaL8No9jGA​
  • Select the Get method to read the JSON value we have submitted to the Blockchain.
    Enter the id: 1. If there is no error, you will get response body:

    {"RGB":"3,252,240","light_status":"true"}​

    With response code 200 – OK.

Verify the Block

  • Navigate to Explore and verify on the last block that event and JSON object were written.

BulbBlockchainUI5

Create an SAPUI5 app to turn on/off the light and change the color.

From SAP Web IDE, clone SAPUI5 app from GitHub and deploy it to SAP Cloud Platform:

  • Navigate to SAP Web IDE from SAP Cloud Platform Cockpit.
  • Right click on the Workspace, select Git and select Clone Repository.
  • Enter URL https://github.com/ferrygun/BulbBlockchainUI5.git and select Clone.
  • Open bulbblockchain.controller.js and take a look at the code highlighted in the red box.

    On onButtonPress function, create the ajax Post method to Hyperledger Fabric with the required authorization header that we got from the step  Hyperledger Fabric Configuration: Test  Chaincode and JSON object defined in the variable data.

    var data = '{"light_status": "' + light_status + '", "RGB": "' + RGB + '"}';
    			console.log(data);
    
    
    			jQuery.ajax({
    				url: "https://hyperledger-fabric.cfapps.eu10.hana.ondemand.com/api/v1/chaincodes/4f0155ae-ba78-44df-93fa-56b705d7de78-com-sap-icn-blockchain-example-helloWorld-events/51/1",
    				cache: false,
    				type: "POST",
    				headers: {
    			        'Authorization':'Bearer eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHBzOi8vcDUyODAzNHRyaWFsLmF1dGhlbnRpY2F0aW9uLmV1MTAuaGFuYS5vbmRlbWFuZC5jb20vdG9rZW5fa2V5cyIsImtpZCI6ImtleS1pZC0xIiwidHlwIjoiSldUIn0.eyJqdGkiOiJhMDFhMjgzYWY2YzY0Nzk4OTdiYzJhZWNkNDdhMzUzMiIsImV4dF9hdHRyIjp7ImVuaGFuY2VyIjoiWFNVQUEiLCJ6ZG4iOiJwNTI4MDM0dHJpYWwiLCJzZXJ2aWNlaW5zdGFuY2VpZCI6ImJiYzcxNzZhLTVkOWItNDlmOC04Njg0LWExYjQ5NTExM2JjMiJ9LCJzdWIiOiJzYi1iYmM3MTc2YS01ZDliLTQ5ZjgtODY4NC1hMWI0OTUxMTNiYzIhYjEwMjYyfG5hLTQyMGFkZmM5LWY5NmUtNDA5MC1hNjUwLTAzODY5ODhiNjdlMCFiMTgzNiIsImF1dGhvcml0aWVzIjpbInVhYS5yZXNvdXJjZSJdLCJzY29wZSI6WyJ1YWEucmVzb3VyY2UiXSwiY2xpZW50X2lkIjoic2ItYmJjNzE3NmEtNWQ5Yi00OWY4LTg2ODQtYTFiNDk1MTEzYmMyIWIxMDI2MnxuYS00MjBhZGZjOS1mOTZlLTQwOTAtYTY1MC0wMzg2OTg4YjY3ZTAhYjE4MzYiLCJjaWQiOiJzYi1iYmM3MTc2YS01ZDliLTQ5ZjgtODY4NC1hMWI0OTUxMTNiYzIhYjEwMjYyfG5hLTQyMGFkZmM5LWY5NmUtNDA5MC1hNjUwLTAzODY5ODhiNjdlMCFiMTgzNiIsImF6cCI6InNiLWJiYzcxNzZhLTVkOWItNDlmOC04Njg0LWExYjQ5NTExM2JjMiFiMTAyNjJ8bmEtNDIwYWRmYzktZjk2ZS00MDkwLWE2NTAtMDM4Njk4OGI2N2UwIWIxODM2IiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInJldl9zaWciOiJjNzJmMDkwOCIsImlhdCI6MTU1MzU5Mjc5NiwiZXhwIjoxNTUzNjM1OTk2LCJpc3MiOiJodHRwOi8vcDUyODAzNHRyaWFsLmxvY2FsaG9zdDo4MDgwL3VhYS9vYXV0aC90b2tlbiIsInppZCI6ImQ4MGY5YTYzLWFjZmItNDhhMC04ODkxLWI0MTA5YTEwMzkxMiIsImF1ZCI6WyJzYi1iYmM3MTc2YS01ZDliLTQ5ZjgtODY4NC1hMWI0OTUxMTNiYzIhYjEwMjYyfG5hLTQyMGFkZmM5LWY5NmUtNDA5MC1hNjUwLTAzODY5ODhiNjdlMCFiMTgzNiIsInVhYSJdfQ.dgv0pRJWjXZ2hN2E8aw6sEiKWPk8Zy8zMN1M6NnzwsTd8zgqWLu06mjBl9bEmH-YjLaYJwo63ksuDCKaj-hUwcAUpDUFJJIKA5lBaD3-CCwAG-LamQcUcfASX5CKDiOs21sPzPAlU2H3ENkU5t03US9XQwf6Hh-iKH7KwesYewEQTKGQFTAWr8I8GPea-Ax5kJebBkzXSM4lIb7xQtY3DjO1LDZiGYVBopxfqBTnD550BKLK1r_MzpkC3olTX5RbrpsUrW8SaeVq-4SAw02uIwXZ_h8hOktrB6LUrpsU15mQ5SKWYcrDGn-b50fL3iwdGE-_cKNJlPU_Kmm8a-rcIOB7aLufXwjm2uzn5gXnP4YAMFmgCfVDQq5iDJxL7vPgH6hiHajGKVdksh3damrU9_RInFKHmdTe2fOOcsQLMiId3JZoFcyWjvkj4YYHTktcoGHQVyCCHzUhh5LYhxKe-MWaV2rX3Fcun1agTc1tT5jvkUtWOa9_-eEORTxTABVHuYTiCInK8iME5TnU8k3BmRYtklTV_CPkOdiTI4UbAkiABIelMQFwRjdt6FPe4BCZOHA_Vv8M4-EdsUx709dmroBmWlRN8UZpiXhsLY0eSeDu4GbU4x58SJBLxCWEPEdeuFG6goWNHRW5szUQ_wb8vosNc018Ae2F45PQ6VuOuJM',
    			        'Content-Type':'application/json'
    			    },
    				data: data,
    				async: true,
    				success: function(sData) {
    					console.log('[POST] /discover-dialog', sData);
    
    					
    				},
    				error: function(sError) {					
    					console.log("Something error!");      
    				}
    			});​

    In JSON object, define the light status and RGB value.

    {
      "light_status": "true",
      "RGB": "3,252,240"
    }
    

    The parameter light_status is true (light is on) and false (light is off), The RGB is the light color space from the combination of red, green and blue colors ranging from 0 to 255.

  • Right click on BulbBlockchainU5, select Deploy and select Deploy to SAP Cloud Platform.
  • Open the app URL.

NodeJS App: Subscriber

Create a NodeJS app subsriber.js to listen to the events emitted by the Chaincode.

Install the library from https://github.com/Bastl34/node-yeelight-wifi.

npm install --save node-yeelight-wifi

Create a NodeJS app subscriber.js and update the accessToken and chaincodeID in the source code.

const WebSocket = require('ws');
const accessToken = '<ACCESS_TOKEN>';
const chaincodeId = '<CHAINCODE_ID>'; 
const url = 'wss://hyperledger-fabric.cfapps.eu10.hana.ondemand.com/api/v1/chaincodes/' + chaincodeId + '/events';
const client = new WebSocket(url, {
    headers: {
        Authorization: 'Bearer ' + accessToken,
    },
});

const Lookup = require("node-yeelight-wifi").Lookup;

let look = new Lookup();
let lightobj;
let light_status = 0;
let RGB;

look.on("detected",(light) => {
    console.log("new yeelight detected: id=" + light.id + ", name="+light.name);
	lightobj = light;
});

client.on('open', function () {
    console.log('Connection open.');
});

client.on('message', function (data) {
    console.log(data);

	data = JSON.parse(data);	
	data = JSON.parse(data.payload);
	light_status = data.light_status;
	RGB = data.RGB;

	console.log("light_status: " + light_status + ", RGB: " + RGB);

	lightobj.setPower(light_status).then(() => {
		console.log("success");
	}).catch((error => {
		console.log("failed",error);
	}));
	
	if(RGB !== "") {
		let red = RGB.split(",")[0];
		let green = RGB.split(",")[1];
		let blue = RGB.split(",")[2];
		let rgb = blue | (green << 8) | (red << 16);
		rgb = rgb.toString(10)

		lightobj.setRGB(rgb).then(() => {
			console.log("RGB success");
		}).catch((error => {
			console.log("failed",error);
		}));
	}

})
client.on('close', function (code, reason) {
    console.log('Connection closed.');
    console.log(code, reason);
});

Run the App

Before you run the app, download Yeelight app for iOS or Android.

Install the light bulb and add it in your app. Check if you can control the light from the app.

enable Control LAN from the app so we can control it from WiFi.

Image result for yeelight lan control area

Now we are ready to run the NodeJS app. Run it with command:

node subscriber.js

The app will try to find the available Yeelight and initiate the websocket connection to Hyperledger Fabric. If the light bulb can be found and socket is established, you will see similar message:

Now set the light status to on and RGB color set to 102,247,54 (light green). Select Send to the Blockchain.

You will see the similar message from NodeJS app.

Navigate to the Explore area to verify that the event was written and check if the light is on with green color.

Congratulations! You have successfully demonstrate how to use the Blockchain to control the smart bulb.

Be the first to leave a comment
You must be Logged on to comment or reply to a post.