CC Blog Projects Research & Design Hub

Smart Home Gateway with PHPoC Black

Part 1: Temperature and Humidity Server

The PHP on Chip Black is a programmable IoT MCU board. In this article series, Raul uses it to develop a smart home gateway prototype. In Part 1, he focuses on its integrated web and WebSocket server capabilities. By leveraging the PHPoC platform’s PHP-inspired language and robust IoT features, he creates a basic server that interfaces with an AHT10 sensor to monitor temperature and humidity, displaying real-time data on a dynamic webpage.

  • How does the PHPoC Black integrate web and WebSocket servers on an MCU?
  • How can temperature and humidity sensors be interfaced using PHPoC and I2C?
  • How do WebSockets enable real-time data updates in embedded web applications?
  • How are HTML, JavaScript, and PHPoC combined for dynamic IoT dashboards?
  • How can a PHP-inspired language simplify embedded IoT development?
  • PHPoC Black
  • PHPoC language
  • AHT10 sensor
  • I2C
  • WebSocket
  • Embedded web server
  • HTML
  • JavaScript
  • Ethernet LAN

PHP on Chip (PHPoC) is a PHP-inspired dialect tailored for embedded systems. It supports a wide range of network protocols, incorporating robust security features such as authentication and encryption algorithms. The board comes with an integrated web server and WebSocket server, enabling the creation of real-time IoT solutions for monitoring and control. It offers versatile interfacing options for external sensors and actuators through digital input/output (I/O), SPI, I2C, UART, and analog inputs, complemented by onboard timers/counters and a real-time clock.

The gateway we will implement connects to local sensors and actuators, while also linking via Wi-Fi to remote nodes, enhancing its monitoring and control reach. It hosts a web-based user interface to interact with the system.

The PHPoC Black is ideal for web developers familiar with PHP but new to embedded programming, as well as for embedded engineers and hobbyists who are eager to explore PHP in a microcontroller context.

In this article series, I’ll demonstrate the development of a smart home gateway prototype using the PHPoC Black. Through this project, I’ll introduce the PHPoC language along with HTML and JavaScript to enthusiasts in the latter group, even if they lack prior web server programming experience. To follow along, you’ll need basic experience with embedded systems development in C/C++, using Arduino, PIC, ARM, or similar platforms.

THE PHPoC PLATFORM

PHPoC is a programming language and Internet of Things (IoT) platform developed by Sollae Systems that simplifies building interconnected systems [1]. Based on the widely used PHP server-side language, PHPoC retains nearly identical syntax, but is tailored for embedded systems. It enables interaction with peripherals through digital I/O, protocol communications (UART, I2C, SPI), analog-to-digital conversion (ADC), timer/counter functions, and a real-time clock (RTC).

As an embedded web server platform, PHPoC also has the capability to interface directly with hardware devices (sensors and actuators). Moreover, beyond serving dynamic web pages, it supports tasks that include sending emails, accessing remote databases, and exchanging data over the Internet. These capabilities allow seamless monitoring and control of machines and devices online, while interacting with hardware peripherals.

The onboard PHPoC firmware includes hardware drivers, a web server, network protocol implementations, and the PHPoC interpreter. Applications are developed by writing PHPoC script files that run in the system’s infinite loop or in response to HTTP requests. The PHPoC can also serve web pages with HTML, CSS, JavaScript, and images. It features an onboard web server and WebSocket server with SSL/TLS encryption. For IoT embedded web server applications, PHPoC bridges the gap between a Raspberry Pi and a standard Arduino board. It enables easy implementation of a robust IoT (PHP-powered) web server, while allowing seamless interfacing with offboard embedded sensors and actuators.

Various hardware options are available from the manufacturer, from dedicated IoT gateways to Arduino-like boards for prototyping. In this article, I will focus on the “PHPoC Black” board, shown in Figure 1, which features wired LAN Ethernet connectivity. An alternative board, the PHPoC Blue, includes a USB Wi-Fi adapter for wireless LAN connectivity.

Figure 1
PHPoC Black board, which features wired LAN Ethernet connectivity.
Figure 1
PHPoC Black board, which features wired LAN Ethernet connectivity.

This article’s primary purpose is to highlight PHPoC’s advanced capabilities, so I will not cover the basics of installing or using the development tools. Abundant beginner resources are available on PHPoC’s website [2], and the platform is very user-friendly. PHPoC features its own Integrated Development Environment (IDE) called the “PHPoC Debugger.” To program the board, simply connect the Debugger to the board by opening the assigned virtual COM port, add PHP script files, libraries, HTML/JavaScript pages, and resources to the file list window, and click the “flash” button to upload all files to the board’s flash memory. Figure 2 shows a screenshot of the PHPoC Debugger with project files ready for editing or flashing to the board’s memory.

Figure 2
PHPoC Debugger IDE.
Figure 2
PHPoC Debugger IDE.

PHPoC’s website offers numerous beginner tutorials, code examples, and libraries for various sensors, actuators, and web-based monitoring/control systems. However, no libraries were available for the I2C sensors I needed for this project, so I adapted a few existing I2C libraries to create the ones required.

EXAMPLE: TEMPERATURE AND HUMIDITY SERVER

To get familiar with the platform, let’s explore a simple example of interfacing a sensor to the PHPoC board and setting up a web server to display sensor data on a webpage. In this introductory example, we will read data from the ASAIR AHT10 temperature and relative humidity sensor via its I2C bus interface, and visualize them graphically on a webpage.

In Figure 2, the file navigator shows the files for this example. All files and folders in this pane are sourced from the PHPoC’s flash memory. As shown, there are five files and a “lib” folder (ignore the shadowed “mmap” folder for now). The first file, “gauge.png,” is an image file containing the gauge graphic design to be displayed on the webpage (Figure 3).

Figure 3
PHPoC Debugger displaying the gauge image.
Figure 3
PHPoC Debugger displaying the gauge image.

The second file, “index.php,” contains the HTML code for the webpage served to the user. The third file, “init.php,” serves as the entry point for code execution. The fourth file, “script.js,” holds JavaScript code required by the HTML page to render dynamic content, and the fifth file, “task0.php,” contains PHP code that interfaces with PHPoC’s onboard hardware and firmware, as well as with offboard hardware. Download links to all Source and Resource files are available on the Circuit Cellar Article Code and Files webpage.

Figure 4
Temperature and relative humidity server circuit schematic.
Figure 4
Temperature and relative humidity server circuit schematic.

Figure 4 illustrates the circuit schematic for the temperature and humidity server, and Figure 5 shows the hooked-up devices ready for testing. Listing 1 presents the HTML code for the user interface webpage. The following is an explanation for those unfamiliar with HTML.

Figure 5
PHPoC board with the AHT10 sensor.
Figure 5
PHPoC board with the AHT10 sensor.
Listing 1
Webpage HTML code.

1 <!DOCTYPE html>2 <html>3 <head>4 	<title>HAG Web Page</title>5 	<meta name=”viewport” content=”width=device-width”>6 	<script src=”script.js”></script>7 </head>8 9 <body>10 	<h1>Home Automation Gateway</h1>11 	<p>WebSocket : <span id=”ws_state_id”>CLOSED</span></p>12 13 	<div style=”float: left; padding: 10px;”>14 		<h2>Temperature</h2>15 		<canvas id=”temp_gauge_id”></canvas>16 	</div>17 18 	<div style=”float: left; padding: 10px;”>19 		<h2>Relative Humidity</h2>20 		<canvas id=”rh_gauge_id”></canvas>21 	</div>22 </body>23 </html>

Line 1 declares that the file contains HTML code, which is enclosed within the <html>…</html> tag pair in lines 2 and 23. Within these tags, there are two sections: the “head” (lines 3–7) and the “body” (lines 9–22).

In the head section, line 4 assigns the webpage’s browser tab name (see the tab name and the small window below the cursor in Figure 6). Line 5 defines a “viewport” metadata parameter that adjusts the visible content area to the device’s screen width, ensuring all webpage elements are displayed without scroll bars, regardless of the device type (e.g., laptop and mobile device). The “script” tag pair in line 6 specifies a JavaScript file, “script.js,” which must be downloaded from the web server to enable dynamic content and interactivity on the webpage.

Figure 6
Monitoring webpage.
Figure 6
Monitoring webpage.

Inside the body section, line 10 defines a level-1 header (using “h1” tags) that displays “Home Automation Gateway” as the main webpage title (Figure 6). Using a “p” tag pair, line 11 creates a text paragraph containing the text “WebSocket: “ followed by a “span” tag pair (a generic inline container) used here to apply specific styling or formatting to its content. This span tag with the ID “ws_state_id,” by default displays the text “CLOSED,” reflecting the initial WebSocket’s state (details on WebSockets to follow). But, this text dynamically updates to “OPEN” after the webpage loads, and establishes communication with the PHPoC’s WebSocket server.

Next, lines 13-16 define a “div” section that aligns (or “floats”) to the left of its container with a 10-pixel (“10px”) padding, as specified in the “style” attribute (line 13). The padding creates inner space within the “div” to separate it from the adjacent “div” section that we will need for a second gauge. Within the “div,” an “h2” sub-title displays the name (“Temperature”), followed by a “canvas” element inside of which the gauge image will be rendered (line 15). Both the gauge name and image appear at the left half of Figure 6. Similarly, lines 18-21 define a second “div” for the relative humidity gauge.

JAVASCRIPT AND WEBSOCKETS

Listing 2 presents the JavaScript code in the “script.js” file, referenced by the HTML code in Listing 1, line 6. This code runs in the web browser to enable dynamic refreshing of gauge values on the webpage. If you are familiar with C/C++ syntax, you will soon notice that JavaScript is quite similar. Lines 1-4 declare global variables, whose purposes become clear upon analyzing the rest of the code. Line 6 sets the init function to be executed immediately after the webpage loads. That function is defined in lines 8-37. Let’s explore what it does.

Listing 2
Webpage JavaScript code.

1 var gauge_canvas_width = 400, gauge_canvas_height = 250;2 var pivot_x = 200, pivot_y = 200;3 var pivot_radius = 22, hand_radius = 180;4 var ws_states;5 6 window.onload = init;7 8 function init() {9 	// Draw temperature gauge10 	var temp_gauge = document.getElementById(“temp_gauge_id”);11 	temp_gauge.width = gauge_canvas_width;12 	temp_gauge.height = gauge_canvas_height;13 	temp_gauge.style.backgroundImage = “url(‘/gauge.png’)”;14 15 	var temp_ctx = temp_gauge.getContext(“2d”);16 	temp_ctx.translate(pivot_x, pivot_y);17 	rotate_gauge_needle(0, 0, “temp_gauge_id”);18 	19 	// Draw relative humidity gauge20 	var rh_gauge = document.getElementById(“rh_gauge_id”);21 	rh_gauge.width = gauge_canvas_width;22 	rh_gauge.height = gauge_canvas_height;23 	rh_gauge.style.backgroundImage = “url(‘/gauge.png’)”;24 25 	var rh_ctx = rh_gauge.getContext(“2d”);26 	rh_ctx.translate(pivot_x, pivot_y);27 	rotate_gauge_needle(0, 0, “rh_gauge_id”);28 	29 	// Open WebSocket to receive sensor states30 	var ws_url = “ws://” +  location.host + “/states”;// ws://192.168.0.109/states31 	ws_states = new WebSocket(ws_url, “csv.phpoc”);32 	document.getElementById(“ws_state_id”).innerHTML = “CONNECTING”;33 	ws_states.onopen  = function(){ document.getElementById(“ws_state_id”).innerHTML = “OPEN” };34 	ws_states.onclose = function(){ document.getElementById(“ws_state_id”).innerHTML = “CLOSED”};35 	ws_states.onerror = function(){ alert(“websocket error “ + this.url) };36 	ws_states.onmessage = ws_get_states;37 }38 function ws_get_states(e_msg) {39 	e_msg = e_msg || window.event; // MessageEvent40 	var states = e_msg.data;41 	const states_arr = states.split(‘,’);42 	43 	// Get and update temperature44 	var temp_state = Number(states_arr[0]);45 	temp_needle_ang = Math.round(temp_state / 100 * 180) + 36; // Displace 20 deg.46 	rotate_gauge_needle(temp_needle_ang, temp_state, “temp_gauge_id”);47 	48 	// Get and update relative humidity49 	var rh_state = Number(states_arr[1]);50 	rh_needle_ang = Math.round(rh_state / 100 * 180);51 	rotate_gauge_needle(rh_needle_ang, rh_state, “rh_gauge_id”);52 }53 function rotate_gauge_needle(angle, value, id) {54 	var gauge = document.getElementById(id);55 	var ctx = gauge.getContext(“2d”);56 	var meas_text = value.toString();57 	58 	ctx.clearRect(-pivot_x, -pivot_y, gauge_canvas_width, gauge_canvas_height);59 	60 	ctx.rotate(angle / 180 * Math.PI); // Degrees conv. to radians61 	ctx.beginPath();62 	ctx.moveTo(-pivot_radius, 0);63 	ctx.lineTo(-hand_radius, 0);64 	ctx.stroke();65 66 	ctx.rotate(-angle / 180 * Math.PI); // Degrees conv. to radians67 	ctx.font = “24px Verdana”;68 	ctx.fillText(meas_text, -20, 50);69 }

Immediately after the page loads, this function uses lines 10–17 to draw the temperature gauge. Line 10 retrieves a reference to the HTML object with the ID “temp_gauge_id.” Line 15 from Listing 1 indicates that this object is the temperature gauge canvas. Using the obtained canvas reference, lines 11–12 set its width and height to match those of the “gauge.png” image, stored in the variables gauge_canvas_width and gauge_canvas_height defined in line 1. Then, line 13 sets the “gauge.png” image as the canvas background, rendering the left gauge shown in Figure 6.

Line 15 retrieves the canvas’ 2D drawing context. Since the canvas element defines a bitmap area on the webpage, we need a reference to its context to draw lines, curves, and other shapes, with various colors, and to perform translations, rotations, and other manipulations. We will use some of these operations to draw the gauge needle over the background image. In that vein, in line 16, we call the temp_ctx.translate() function to move the canvas origin —located by default at its top-left corner— to the position (pivot_x, pivot_y), which is (200, 200). This point serves as the needle’s rotation pivot and coincides with the gray circle’s center at the gauge bottom-center in Figure 3. In line 17 we call the rotate_gauge_needle() function to draw the needle in its default 0 position. Lines 20–27 perform similar operations for the relative humidity gauge.

The code in lines 30–36 sets up a “WebSocket” communication session to receive data from the PHPoC. WebSocket is a protocol that enables sending and receiving data to/from a server without refreshing the webpage. To open the WebSocket (line 31), we need the remote server’s endpoint Uniform Resource Locator (URL). In our case, this URL is something like “ws://192.168.0.8/states,” where 192.168.0.8 is the PHPoC server’s IP address assigned by the Local Area Network (LAN) router, and “states” is the resource name on the server we want to query (see line 30). Similarly, a corresponding WebSocket needs to be opened on the PHPoC server with “states” as its resource name.

In line 31, the second argument (csv.phpoc) specifies the protocol to be used, indicating that we expect data in Comma-Separated Values (CSV) format. Next, in line 32, we obtain a reference to the HTML element with the ID “ws_state_id.” This “span” element displays on the webpage the WebSocket’s status that shows “CLOSED” by default (see line 11 in Listing 1). We need this reference to update the status. So, in line 32, at the same time we obtain the reference, we access the element’s “innerHTML” property (which holds “CLOSED” as default text), and update it to “CONNECTING” to reflect the new state.

The WebSocket opening in line 31 is an asynchronous task, meaning we cannot predict exactly when the socket will be ready or if it might fail. Following the event-driven model, we must listen for events generated by the web browser to track the WebSocket’s status. The “ws_states” WebSocket object created in line 31 has an “onopen’”attribute that allows attaching a callback function to be executed when the “onopen” event is triggered upon a successful WebSocket opening. Line 33 attaches to this attribute the function(){…} anonymous callback. This function is anonymous because it uses the generic name “function” instead of a specific name. Its body, enclosed in curly brackets, contains just one line:

document.getElementById(“ws_state_id”).innerHTML = “OPEN”.

This statement updates the “innerHTML” property of the “ws_state_id” element to display the text “OPEN,” which occurs only when an “onopen” event is received, resulting in the rendering of the aforementioned text on the webpage.

Line 34 handles the “onclose” event, triggered when the WebSocket closes for any reason. Line 35 performs a similar task for the “onerror” event, but instead of updating the “ws_state_id” element’s text, it opens an alert dialog on the webpage, displaying an error message (for instance: “websocket error 192.168.0.8”). Finally, we also need to listen for the “onmessage” event, generated each time new data is received. In line 36, we attach the ws_get_states callback function to handle the reception of remote sensor data updates from the PHPoC board.

Going forward, lines 38-52 define the aforementioned ws_get_states() function. Let’s see how it works. In line 39, we retrieve the “e_msg” WebSocket data object, which contains multiple attributes, particularly the “data” attribute, which holds the CSV string with the sensor readings received from the PHPoC server. We extract this data from the object in line 40 and, in line 41, split the CSV string into the states_arr array specifying the comma character as delimiter. A received CSV string might look, for instance, like: “25,55,” where the first value is the temperature and the second is the relative humidity. After line 41 is executed, “states_arr[0]” will contain the substring “25,” and “states_arr[1]” will contain the substring “55.”

Next, in line 44, we convert the first substring to a number and store it in the temp_state variable. Then, in line 45, we calculate the gauge needle angle to display the received value. We do this by dividing the value by 100 (the temperature range is 0–100°C) and multiplying by 180 angle degrees (the gauge’s display range). For the temperature gauge, we also add 36 angle degrees to shift negatively the range by 20°C, allowing the display of temperatures between –20°C and +80°C. Next, in line 46, we call the rotate_gauge_needle() function, passing as arguments the computed angle, the temperature value string, and the HTML canvas element ID (“temp_gauge_id”) that contains the temperature gauge.

Lines 49–51 perform similar operations for relative humidity. We display 0–100% humidity values over a 0–180 angle degree range, but no range displacement is required since there are no negative humidity values.

Finally, lines 53–68 define the function that draws the gauge needle. In line 54, we retrieve the gauge canvas reference using the argument from the id function parameter. In line 55, we obtain the canvas’ 2D context reference. In line 56, we take the argument from the value function parameter containing the sensor value and convert it to string. Line 58 clears the rectangular area covering the entire canvas to erase the previously drawn needle. (The gauge image used as background isn’t affected.) The first two arguments to clearRect() specify the rectangle’s upper-left corner, and the last two specify the lower-right corner. The first two coordinates are negative due to the context translation performed earlier in line 16.

In line 60, after converting the angle from degrees to radians, we rotate the canvas to the new needle angle, aligning its x-axis with the required needle angle. This will allow us to draw the needle by varying only the x-coordinate while keeping the y-coordinate at zero. In line 61, we begin drawing the needle by calling beginPath(). In line 62, we move to the starting coordinates of the needle line path, “(-pivot_radius, 0),” and then draw a straight line to the coordinates “(-hand_radius, 0),” setting the needle’s body length (line 63). Line 64 strokes the line that’s seen as the needle body over the gauge image on the canvas. In line 66, to display the numeric value right below the needle’s pivot point, we rotate the canvas back to its default horizontal position by using the same angle but with opposite sign. In line 67, we set the font size and type, and in line 68, at coordinates (-20, 50), we render the numeric value contained in the meas_text variable. This is shown as “25” below the gauge’s needle pivot in Figure 6. A similar procedure is followed as well to render the relative humidity gauge needle at the right side of the webpage.

RUNNING PHP ON THE MCU

Now, let’s examine the “task0.php” file in Listing 3, which contains the PHP code that runs on the PHPoC board. This code reads from the AHT10 sensor and sends temperature and relative humidity values to the browser via WebSocket communication.

Listing 3
Webpage PHP code.

1 <?php 2 if(_SERVER(“REQUEST_METHOD”))3 	exit; // avoid php execution via http request4 5 include “/lib/sn_tcp_ws.php”;6 include_once “lib/aht10.php”;7 8 define(“REFRESH_PERIOD”, 1); // 1 second9 $last_rel_hum = 0;10 $last_temp = 0;11 $count = 1;12 $last_time = 0;13 14 echo “Setting up AHT10 and socket...\r\n”;15 aht10_setup(0);16 ws_setup(0, “states”, “csv.phpoc”);17 18 while(1) {19 	if((time() - $last_time) > REFRESH_PERIOD) {20 		$last_time = time();21 22 		echo “------ Reading AHT10 ------\r\n”;23 		aht10_read_sensor();  24 		$temp = round(aht10_get_temp());    25 		$rel_hum = round(aht10_get_hum());26 27 		echo “$count: temp: $temp°C | rh: $rel_hum%\r\n”;28 		$count = $count + 1;29 		30 		if(ws_state(0) == TCP_CONNECTED) { // Send states31 			$states = “$temp,$rel_hum\r\n”; // Example: “21,54”32 			ws_write(0, $states);33 		}34 	}35 }36 ?>

As you can see, in a PHP script, code is enclosed within the tags <?php…?> (see lines 1 and 36). Since PHP scripts on a web server can be invoked directly by a web browser, lines 2–3 prevent direct execution on this specific script whenever a request is received directly from a client via HTTP. This ensures this code remains internal to the system, because in this particular case, users do not need to access it directly. In other cases, however, clients may be allowed to request direct PHP code execution via HTTP requests.

Lines 5–6 include two libraries: “sn_tcp_ws.php” is provided by the platform for WebSocket communications and “aht10.php” is the one I wrote to interface with the AHT10 sensor. Both libraries are located inside the “lib” folder along with the “sd_340.php” library used to access the PHPoC onboard peripherals (see the file list pane in Figure 7). As with most libraries, generally you don’t need to understand their internals; you just need to know which specific functions to call to perform the tasks you require.

Figure 7
Project libraries in the Debugger file list pane.
Figure 7
Project libraries in the Debugger file list pane.

Line 8 defines a REFRESH_PERIOD constant of 1 second, and lines 9–12 define four variables. PHP is well-known for using the “$” symbol as the first (mandatory) character in variable names. Line 14 prints a debug string to the Debugger console (see the “Output” bottom-left pane in Figure 7). Line 15 calls the aht10_setup() function from the “aht10.php” library to initialize the sensor, and line 16 calls ws_setup() from the “sn_tcp_ws.php” library to open the WebSocket. The first argument in the last function call, “0,” is the socket number—PHPoC supports only five sockets simultaneously (0–4). The second argument “states” is the resource name for the WebSocket, and the third argument specifies the protocol to send data as CSV strings.

Next, lines 18–35 define an infinite loop—typical in embedded systems— to handle all the repetitive tasks. The “if” statement in line 19, along with the $last_time variable makes it possible to set up a non-blocking delay. It accomplishes that by comparing the current time obtained by calling the time() function, with the last stored time in the $last_time variable to check if REFRESH_PERIOD seconds (1 second in our case) have elapsed. If so, lines 20–33 execute. Line 22 prints a debug message to the console, and line 23 calls the aht10_read_sensor() library function to read temperature and humidity from the AHT10. Line 24 calls aht10_get_temp() to get the temperature, rounds its value to an integer, and assigns it to the $temp variable. Line 25 does something similar for relative humidity.

Line 27 prints another debug string to the console that includes a reading count (just for debugging purposes) along with the temperature and humidity values. Incidentally, this code line demonstrates PHP’s flexible string concatenation capabilities. As you can see, the string “$count: temp: $temp°C | rh: $rel_hum%\r\n” mixes variable names and regular text. For the final concatenation result, variables starting with “$” are replaced with their values, while other text remains unchanged. In the bottom-left pane of Figure 7 you can see examples of the concatenation result, such as “2: temp: 21°C | rh: 54%.”

Finally, line 30 checks if the WebSocket remains open. Line 31 concatenates the sensor values into a CSV string—for instance: “21,54” if the last temperature value is “21” and the relative humidity is 54.” As a last step, line 32 sends this CSV string to the web client via the WebSocket. As it is implied by the REFRESH_PERIOD constant defined in line 8, these sensor values are refreshed every second.

The last remaining file we haven’t discussed yet, “init.php,” is very simple and contains just the following line of code:

<?php

system(“php task0.php”);

?>

This file is the code execution entry point, and it only specifies that the “task0.php” file must be executed after running the system. To run the system, first hit the “Run” button in the Debugger, then go to the Debugger’s “Function > System information > IP Address” menu to get the PHPoC’s assigned IP address and open it in a web browser.

— ADVERTISMENT—

Advertise Here

CONCLUSION

In this first part of the article series, I laid the foundation for building a DIY smart home gateway using the PHPoC Black IoT platform, focusing on its integrated web- and WebSocket-server capabilities. By leveraging the PHPoC platform’s PHP-inspired language and robust IoT features, we created a basic server that interfaces with an AHT10 sensor to monitor temperature and humidity, displaying real-time data on a dynamic webpage. The step-by-step exploration of HTML, JavaScript, and PHPoC scripts demonstrated how to bridge embedded systems with web technologies, making the platform accessible to regular embedded enthusiasts without web server development experience.

I hope I managed to showcase the PHPoC Black’s potential as a versatile IoT solution, setting the stage for further enhancements. In Part 2 of this article series, I will be integrating additional sensors, actuators, and remote connectivity for a fully realized smart home system. Once you understand the basics outlined here, it will be mostly a matter of repeating the same approach for newly added devices, while at the same time adding a bit more complex logic and code to get a reasonably capable home automation gateway. Stay tuned!

REFERENCES
[1] What is PHPoC?, https://www.phpoc.com/what_is_phpoc.php
[2] Let’s learn PHPoC!, https://www.phpoc.com/learn.php

SOURCES
PHPoC Black:
https://www.phpoc.com/phpoc_black.php
ASAIR AHT10 High Precision Digital Temperature and Humidity Sensor:
https://www.amazon.com/ACEIRMC-Precision-Temperature-Measurement-Communication/dp/B09SD2BDJG
P4S-341 (PHPoC Black) User Manual:
https://www.phpoc.com/support/manual/p4s-341_user_manual
phpoc_man Projects:
https://www.hackster.io/phpoc_man/projects
PHP Introduction:
https://www.w3schools.com/php/php_intro.asp
An Introduction to WebSockets:
https://medium.com/@yassimortensen/an-introduction-to-websockets-10b131182559

Code and Supporting Files

PUBLISHED IN CIRCUIT CELLAR MAGAZINE • JULY 2025 #420 – Get a PDF of the issue

Keep up-to-date with our FREE Weekly Newsletter!

Don't miss out on upcoming issues of Circuit Cellar.


Note: We’ve made the Dec 2022 issue of Circuit Cellar available as a free sample issue. In it, you’ll find a rich variety of the kinds of articles and information that exemplify a typical issue of the current magazine.

Would you like to write for Circuit Cellar? We are always accepting articles/posts from the technical community. Get in touch with us and let's discuss your ideas.

Sponsor this Article
 |  + posts

Raul Alvarez Torrico has a B.E. in electronics engineering and is the founder of TecBolivia, a company offering services in physical computing and educational robotics in Bolivia. In his spare time, he likes to experiment with wireless sensor networks, robotics and artificial intelligence. He also publishes articles and video tutorials about embedded systems and programming in his native language (Spanish), at his company’s web site www.TecBolivia.com. You may contact him at raul@tecbolivia.com

Supporting Companies

Upcoming Events


Copyright © KCK Media Corp.
All Rights Reserved

Copyright © 2026 KCK Media Corp.

Smart Home Gateway with PHPoC Black

by Raul Alvarez Torrico time to read: 18 min