Jekyll2021-07-10T10:28:38+00:00https://odd-one-out.serek.eu/Odd One OutMy blog about geeky projectsPoul Serekhttps://Ox3.serek.eu/about/Wireless charging a Kindle Paperwhite2019-01-05T11:28:08+00:002019-01-04T23:00:00+00:00https://odd-one-out.serek.eu/projects/wireless-charging-kindle-paperwhite
<p><img src="/assets/images/wireless-charging-kindle-paperwhite-feature.jpg" alt="" /></p>
<p>In my quest to fully eliminate any micro-usb devices I stumbled upon my old Kindle Paperwhite which is one of my last devices to use micro-usb. A neat little trick if you are using a case with the Kindle is to purchase a wireless charging module to add between the Kindle and the case.</p>
<figure>
<noscript><img src="/assets/images/wireless-charging-kindle-paperwhite-receiver.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/wireless-charging-kindle-paperwhite-receiver.jpg" alt="" class="lazyload fade-in" />
<figcaption>A micro-usb wireless receiver</figcaption>
</figure>
<p>For just 13 USD for the wireless charging receiver and another 14 USD for the wireless charger it works great! It does make the Kindle a tiny bit more bulky, but nothing I notice using it day to day.</p>
<figure>
<noscript><img src="/assets/images/wireless-charging-kindle-paperwhite-case.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/wireless-charging-kindle-paperwhite-case.jpg" alt="" class="lazyload fade-in" />
<figcaption>A micro-usb wireless receiver attached to the Kindle Paperwhite</figcaption>
</figure>
<p>It takes a few tries the first time to place the Kindle correctly on the wireless charging pad since it is not completely center. A tip - use the micro-usb connector as a point to center it.</p>
<figure>
<noscript><img src="/assets/images/wireless-charging-kindle-paperwhite-receiver-attached.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/wireless-charging-kindle-paperwhite-receiver-attached.jpg" alt="" class="lazyload fade-in" />
<figcaption>A micro-usb wireless receiver attached to the Kindle Paperwhite. As it is not completely center it takes a few tries the first time charging it.</figcaption>
</figure>
<h2 id="parts">Parts</h2>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<ul>
<li><a href="https://www.amazon.com/gp/product/B01DLYF0Q0/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B01DLYF0Q0">Nillkin Wireless Charger Receiver</a></li>
<li><a href="https://www.amazon.com/gp/product/B0756Z8X82/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B0756Z8X82">Anker Power port wireless 5 pad</a></li>
<li>Any 1 amp USB charger (using a 0.5 amp charger failing to charge it through the case)</li>
</ul>
<p>This trick should also work on phones or similar devices that use a case.</p>
<p><a href="https://odd-one-out.serek.eu/projects/wireless-charging-kindle-paperwhite/" rel="nofollow">Wireless charging a Kindle Paperwhite</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Removing the need to old micro-usb cables by retrofitting wireless charging to my old Kindle Paperwhite e-ink reader!Server idling at 9 watt2018-09-23T00:00:00+00:002018-09-23T22:24:00+00:00https://odd-one-out.serek.eu/projects/low-power-server
<p><img src="/assets/images/low-power-server-feature.jpg" alt="" /></p>
<p>I was on the lookout for a proper low power server, which meant</p>
<ul>
<li>Consuming less than 10 watts idle</li>
<li>Silent</li>
<li>ECC memory</li>
<li>Several PCIe expansion slots</li>
<li>Relatively small</li>
</ul>
<p>I did own a Kaby lake Intel NUC which was passively cooled, but while the idle power consumption was great at around 6 watts, it lacked room for expansion (only a single M.2 and SATA slot, no PCIe slots) and did not support ECC memory. The idle temperatures was also too high, my M.2 hard disk was around 38 degrees Celsius idle with a room temperature of 25 degrees.</p>
<p>I ended up with a small micro-atx motherboard with a case not much larger than the board itself.</p>
<figure>
<noscript><img src="/assets/images/low-power-server-case.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-case.jpg" alt="" class="lazyload fade-in" />
<figcaption>The Cooltek C2 case is a small case with plenty of room for a large silent CPU cooler.</figcaption>
</figure>
<p>The setup consists of</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<ul>
<li><a href="http://www.fujitsu.com/global/products/computing/peripheral/mainboards/extended-lifecycle-main/pmod-177972.html">Fujitsu D3417-B2 motherboard</a></li>
<li><a href="https://www.amazon.de/dp/B07BG6BMY7/" rel="nofollow" data-amazon-asin="[uk][de][es][it][fr]B07BG6BMY7[us][ca]">A single Samsung 16 GB ECC memory module (M391A2K43BB1-CRC)</a></li>
<li><a href="https://www.amazon.com/dp/B01NADEVZI/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B01NADEVZI">Intel Pentium G4600</a></li>
<li><a href="https://www.amazon.com/dp/B00XUVGLEU/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00XUVGLEU">Noctua NH-D15S CPU cooler</a> with an included 140mm fan</li>
<li><a href="https://www.amazon.com/dp/B00AED7XFI/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00AED7XFI">Noctua NF-A15 PWM 150mm case fan</a></li>
<li><a href="https://www.aliexpress.com/item/Jonsbo-C2-Black-C2BK-HTPC-ITX-Mini-computer-case-in-aluminum-support-3-5-HDD-USB3/32718835069.html" rel="nofollow">Cooltek C2 case</a></li>
<li><a href="https://www.amazon.com/dp/B005TWE6B8/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B005TWE6B8">PicoPSU 160XT</a> power supply</li>
<li><a href="https://www.amazon.com/dp/B005TWE6B8/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B001W3UYLY">60 watt power brick</a></li>
<li>3 M.2 SATA hard disks (single Transcend MTS400 32GB boot disk and two <a href="https://www.amazon.com/dp/B01L80DH1Y/" rel="nofollow" data-amazon-asin="[us][ca]][uk][de][es][it][fr]B01L80DH1Y">1 terabyte Crucial MX300</a></li>
<li>Two <a href="https://www.amazon.com/dp/B073RHHYCM/" rel="nofollow" data-amazon-asin="[us][ca]][uk][de][es][it][fr]B073RHHYCM">Ekwaterblocks EK-RAM M.2 Nvme Heatsink Kit Black</a></li>
<li><a href="https://www.amazon.com/dp/B01LZQGZ95/" rel="nofollow" data-amazon-asin="[us][ca]][uk][de][es][it][fr]B01LZQGZ95">IOCrest 3.5” 2.5” HDD / SSD Mounting Bracket for PCI Slot</a></li>
<li><a href="https://www.amazon.de/dp/B00PIGON4U/" rel="nofollow" data-amazon-asin="[uk][de][es][it][fr]B00PIGON4U[us][ca]B00J4UYAXK">DELOCK Converter 4x SATA 7pin > 4x M.2 NGFF</a></li>
</ul>
<p>Which resulted in a server which is silent and consumes only 8-9 watts idle with 3 hard disks running Ubuntu 16.04.3 server and hosting 10 LXD containers. The only thing connected to the server is the power brick and an ethernet cable for the network. No mouse, keyboard or monitor since these consume some additional power. Some details of the build:</p>
<h2 id="power-consumption">Power consumption</h2>
<p>The PicoPSU with a low wattage power brick does the trick at maintaining a good power efficiency at very low power consumption. When switching to a 192 watt power brick the idle power is around 11-12 watts so the choice of power brick does matter. I have a feeling that it is possible to find an even more efficient combination than I have.</p>
<h2 id="heat">Heat</h2>
<p>The the 140mm and 150mm fans does a very good job at keeping the whole setup cool. The case fan at the bottom draws air inside the case and directs it directly at the hard disks which have added heatsinks.</p>
<figure>
<noscript><img src="/assets/images/low-power-server-hard-disks.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-hard-disks.jpg" alt="" class="lazyload fade-in" />
<figcaption>3.5 inch SATA adapter capable of mounting 4 M.2 hard disks.</figcaption>
</figure>
<p>The massive CPU cooler takes up half the space in the small case and does a good job at keeping the CPU cool. The hard disks stays at around 33 degrees Celsius when idle and the CPU at 30 degrees.</p>
<figure>
<noscript><img src="/assets/images/low-power-server-cooler.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-cooler.jpg" alt="" class="lazyload fade-in" />
<figcaption>Massive cooler that barely fits - and only because I use an external power supply.A low profile cooler and a regular ATX power supply could have worked here instead, but I went for a more silent build.</figcaption>
</figure>
<p>It should be possible to disconnect one of the fans, maybe even both, for an even lower idle power consumption, but I prefer to have some additional cooling.</p>
<h2 id="noise">Noise</h2>
<p>With two large fans and a massive CPU cooler, the whole setup is dead silent. I need to put my ear right next to the case to hear a hint of noise. I have been running this setup for 3 months without and it is still silent!</p>
<h2 id="size">Size</h2>
<figure>
<noscript><img src="/assets/images/low-power-server-case.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-case.jpg" alt="" class="lazyload fade-in" />
<figcaption>The Cooltek C2 case is a small case with plenty of room for a large silent CPU cooler.</figcaption>
</figure>
<p>The case is quite small, but not near as small as the Intel NUC systems. It is however small enough to be hidden away in a closet or shelf - in my case in a small wooden beer crate.</p>
<h2 id="expansion">Expansion</h2>
<p>The case is a very tight fit with room for 2 additional PCIe slots since the third is taken up with the hard disk adapter.</p>
<figure>
<noscript><img src="/assets/images/low-power-server-pcie.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-pcie.jpg" alt="" class="lazyload fade-in" />
<figcaption>PCI mounting bracket for hard disks. The M.2 hard disks are mounted upside down to get the full cooling from the bottom fan.</figcaption>
</figure>
<p>The adapter is strictly not needed since I could mount it on the case front or side panel with some double-sided tape / glue. I could have gotten away with a smaller CPU cooler to free up some internal space, but prefer better cooling.</p>
<p>I have since replaced the PCI mounting bracket and DELOCK Converter to two <a href="https://www.amazon.com/dp/B01IR05DLK/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B01IR05DLK">StarTech 3-port M.2 PCI adapter</a>.</p>
<figure>
<noscript><img src="/assets/images/low-power-server-pci-adapters-inside.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-pci-adapters-inside.jpg" alt="" class="lazyload fade-in" />
<figcaption>Two 3-port M.2 PCI adapters makes for a cleaner and more versatile setup</figcaption>
</figure>
<p>Much more compact setup and added benefit of a net gain of two additional PCI M.2 slots. Does add a bit of flashing lights in the rear!</p>
<figure>
<noscript><img src="/assets/images/low-power-server-pci-adapters.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/low-power-server-pci-adapters.jpg" alt="" class="lazyload fade-in" />
<figcaption>Two 3-port M.2 PCI adapters seen from outside the case</figcaption>
</figure>
<h2 id="conclusion">Conclusion</h2>
<p>Been running this setup for months with no issues and the average power consumption measured from the wall socket has been 9 watts - not bad!</p>
<p><a href="https://odd-one-out.serek.eu/projects/low-power-server/" rel="nofollow">Server idling at 9 watt</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/A proper server supporting ECC memory and 3 PCIe slots, without the noise, heat issues and high power consumption. Idling at only 8-9 watt - measured from the power outlet!ESP8266 NodeMCU - OLED display using SPI2016-04-16T00:00:00+00:002016-04-16T21:19:17+00:00https://odd-one-out.serek.eu/projects/esp8266-nodemcu-oled-display-spi
<p><img src="/assets/images/esp8266-nodemcu-oled-display-spi-feature.jpg" alt="" /></p>
<p>I bought a $4 1 inch OLED SPI display that I wanted to use with my ESP8266 development board. By using an online <a href="http://nodemcu-build.com">service</a> to create a streamlined NodeMCU firmware this was a breeze!</p>
<h2 id="nodemcu-with-the-correct-modules">NodeMCU with the correct modules</h2>
<p>Flash the ESP8266 with a version of NodeMCU that contains the following modules:</p>
<ul>
<li>bit</li>
<li>SPI</li>
<li>U8G</li>
</ul>
<p>Follow my post <a href="/projects/esp8266-nodemcu-dht22-custom-modules-firmware/">here</a> on how to built a custom NodeMCU firmware the easy way!</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-oled-display-spi-modules.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-oled-display-spi-modules.png" alt="" class="lazyload fade-in" />
<figcaption>Custom NodeMCU build for OLED SPI displays</figcaption>
</figure>
<p>If you need help flashing the firmware you can take a look at my guide <a href="/projects/esp8266-development-kit-nodemcu-firmware-update-os-x/">here</a>.</p>
<h2 id="parts">Parts</h2>
<p>If you don’t mind waiting a few weeks I would recommend buying from AliExpress as I have done for the lowest price and free shipping, even to Europe! Amazon, even with Amazon Prime is just a bit too expensive.</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<table>
<thead>
<tr>
<th>Part</th>
<th>Ali Express</th>
<th>Amazon</th>
</tr>
</thead>
<tbody>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B010O1G1ES/" rel="nofollow" data-amazon-asin="[us]B010O1G1ES[ca]B019FBLEYU[uk]B010N1SPRK[de]B0182JOWOK[es][it][fr]">ESP8266 development board</a></td>
<td><a href="https://www.aliexpress.com/item/V2-4M-4FLASH-NodeMcu-Lua-WIFI-Networking-development-board-Based-ESP8266/32448662166.html" rel="nofollow">$4.2</a></td>
<td><a href="https://www.amazon.com/dp/B010O1G1ES/" rel="nofollow" data-amazon-asin="[us]B010O1G1ES[ca]B019FBLEYU[uk]B010N1SPRK[de]B0182JOWOK[es][it][fr]">$9</a></td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B01KFSXMR4/" rel="nofollow" data-amazon-asin="[us]B01KFSXMR4[uk][it][fr]B01KUF1CDS[de][es]B010B1UPDE">0.96 inch 128X64 OLED SPI module</a></td>
<td><a href="https://www.aliexpress.com/item/0-96-blue-0-96-inch-OLED-module-New-128X64-OLED-LCD-LED-Display-Module-For/32595649930.html" rel="nofollow">$4.1</a></td>
<td><a href="https://www.amazon.com/dp/B01KFSXMR4/" rel="nofollow" data-amazon-asin="[us]B01KFSXMR4[uk][it][fr]B01KUF1CDS[de][es]B010B1UPDE">$10.7</a></td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B0084A7PI8/" rel="nofollow" data-amazon-asin="[us][ca][es]B0084A7PI8[uk][de]B00JGFDKBQ[it][fr]B00PQC72ZS">breadboard</a></td>
<td><a href="https://www.aliexpress.com/item/1pcs-Quality-mini-bread-board-breadboard-8-5CM-x-5-5CM-400-holes-For-expansion-arduino/1906352269.html" el="nofollow">$1.2</a></td>
<td><a href="https://www.amazon.com/dp/B0084A7PI8/" rel="nofollow" data-amazon-asin="[us][ca][es]B0084A7PI8[uk][de]B00JGFDKBQ[it][fr]B00PQC72ZS">$5.2</a></td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B00B5RJF1M/" rel="nofollow" data-amazon-asin="[us]B00B5RJF1M[ca]B0087ZDSV8[uk]B004S0XA1O[de]B00IYUWT2A[es][it][fr]">10K resistor</a></td>
<td><a href="https://www.aliexpress.com/item/100pcs-10k-ohm-1-4W-10k-Metal-Film-Resistor-10kohm-0-25W-1-ROHS/32577051768.html" rel="nofollow">$0.7</a></td>
<td><a href="https://www.amazon.com/dp/B00B5RJF1M/" rel="nofollow" data-amazon-asin="[us]B00B5RJF1M[ca]B0087ZDSV8[uk]B004S0XA1O[de]B00IYUWT2A[es][it][fr]">$4.9</a></td>
</tr>
<tr>
<td><a href="https://www.amazon.com/dp/B014JOV4TI/" rel="nofollow" data-amazon-asin="[us]B014JOV4TI[ca]B0002H7AIQ[uk]B01B7M5S6K[de]B01B4HO30K[es]B01GQOJY7I[it]B01GZ2LP82[fr]B01IX7WMAM">Various breadboard wires</a></td>
<td><a href="https://www.aliexpress.com/af/breadboard%25252dwires.html?SearchText=breadboard+wires&blanktest=0&origin=n&jump=afs" rel="nofollow">$2.6</a></td>
<td><a href="https://www.amazon.com/dp/B014JOV4TI/" rel="nofollow" data-amazon-asin="[us]B014JOV4TI[ca]B0002H7AIQ[uk]B01B7M5S6K[de]B01B4HO30K[es]B01GQOJY7I[it]B01GZ2LP82[fr]B01IX7WMAM">$5.9</a></td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$12.8</td>
<td>$35.7</td>
</tr>
</tbody>
</table>
<h2 id="hardware-setup">Hardware setup</h2>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-oled-display-spi-fritzing.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-oled-display-spi-fritzing.png" alt="" class="lazyload fade-in" />
<figcaption>Connecting an inexpensive OLED display using SPI</figcaption>
</figure>
<h2 id="code">Code</h2>
<p>To get started I cheated a bit and used the test code from the U8G library from Github <a href="https://github.com/nodemcu/nodemcu-firmware/tree/master/lua_examples/u8glib">here</a>. I downloaded the file <a href="https://github.com/nodemcu/nodemcu-firmware/blob/master/lua_examples/u8glib/u8g_graphics_test.lua">u8g_graphics_test.lua</a> and changed line 158 to</p>
<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">--init_i2c_display()</span>
</code></pre></div></div>
<p>and line 159 to</p>
<div class="language-lua highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">init_spi_display</span><span class="p">()</span>
</code></pre></div></div>
<p>Then I renamed the file to <code class="highlighter-rouge">init.lua</code> and uploaded the file to the ESP8266. The modified file can also be copied from here:</p>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
</pre></td><td class="code"><pre><span class="c1">-- ***************************************************************************</span>
<span class="c1">-- Graphics Test</span>
<span class="c1">--</span>
<span class="c1">-- This script executes several features of u8glib to test their Lua bindings.</span>
<span class="c1">--</span>
<span class="c1">-- Note: It is prepared for SSD1306-based displays. Select your connectivity</span>
<span class="c1">-- type by calling either init_i2c_display() or init_spi_display() at</span>
<span class="c1">-- the bottom of this file.</span>
<span class="c1">--</span>
<span class="c1">-- ***************************************************************************</span>
<span class="c1">-- setup I2c and connect display</span>
<span class="k">function</span> <span class="nf">init_i2c_display</span><span class="p">()</span>
<span class="c1">-- SDA and SCL can be assigned freely to available GPIOs</span>
<span class="kd">local</span> <span class="n">sda</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1">-- GPIO14</span>
<span class="kd">local</span> <span class="n">scl</span> <span class="o">=</span> <span class="mi">6</span> <span class="c1">-- GPIO12</span>
<span class="kd">local</span> <span class="n">sla</span> <span class="o">=</span> <span class="mh">0x3c</span>
<span class="n">i2c</span><span class="p">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">sda</span><span class="p">,</span> <span class="n">scl</span><span class="p">,</span> <span class="n">i2c</span><span class="p">.</span><span class="n">SLOW</span><span class="p">)</span>
<span class="n">disp</span> <span class="o">=</span> <span class="n">u8g</span><span class="p">.</span><span class="n">ssd1306_128x64_i2c</span><span class="p">(</span><span class="n">sla</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1">-- setup SPI and connect display</span>
<span class="k">function</span> <span class="nf">init_spi_display</span><span class="p">()</span>
<span class="c1">-- Hardware SPI CLK = GPIO14</span>
<span class="c1">-- Hardware SPI MOSI = GPIO13</span>
<span class="c1">-- Hardware SPI MISO = GPIO12 (not used)</span>
<span class="c1">-- CS, D/C, and RES can be assigned freely to available GPIOs</span>
<span class="kd">local</span> <span class="n">cs</span> <span class="o">=</span> <span class="mi">8</span> <span class="c1">-- GPIO15, pull-down 10k to GND</span>
<span class="kd">local</span> <span class="n">dc</span> <span class="o">=</span> <span class="mi">4</span> <span class="c1">-- GPIO2</span>
<span class="kd">local</span> <span class="n">res</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1">-- GPIO16</span>
<span class="n">spi</span><span class="p">.</span><span class="n">setup</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">spi</span><span class="p">.</span><span class="n">MASTER</span><span class="p">,</span> <span class="n">spi</span><span class="p">.</span><span class="n">CPOL_LOW</span><span class="p">,</span> <span class="n">spi</span><span class="p">.</span><span class="n">CPHA_LOW</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="mi">8</span><span class="p">)</span>
<span class="n">disp</span> <span class="o">=</span> <span class="n">u8g</span><span class="p">.</span><span class="n">ssd1306_128x64_hw_spi</span><span class="p">(</span><span class="n">cs</span><span class="p">,</span> <span class="n">dc</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1">-- graphic test components</span>
<span class="k">function</span> <span class="nf">prepare</span><span class="p">()</span>
<span class="n">disp</span><span class="p">:</span><span class="n">setFont</span><span class="p">(</span><span class="n">u8g</span><span class="p">.</span><span class="n">font_6x10</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">setFontRefHeightExtendedText</span><span class="p">()</span>
<span class="n">disp</span><span class="p">:</span><span class="n">setDefaultForegroundColor</span><span class="p">()</span>
<span class="n">disp</span><span class="p">:</span><span class="n">setFontPosTop</span><span class="p">()</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">box_frame</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"drawBox"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawBox</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawBox</span><span class="p">(</span><span class="mi">10</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="s2">"drawFrame"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawFrame</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="o">+</span><span class="mi">30</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">10</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawFrame</span><span class="p">(</span><span class="mi">10</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="mi">15</span><span class="o">+</span><span class="mi">30</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">disc_circle</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"drawDisc"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawDisc</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">18</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawDisc</span><span class="p">(</span><span class="mi">24</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="mi">16</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="s2">"drawCircle"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawCircle</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">18</span><span class="o">+</span><span class="mi">30</span><span class="p">,</span> <span class="mi">9</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawCircle</span><span class="p">(</span><span class="mi">24</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="mi">16</span><span class="o">+</span><span class="mi">30</span><span class="p">,</span> <span class="mi">7</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">r_frame</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"drawRFrame/Box"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawRFrame</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">30</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawRBox</span><span class="p">(</span><span class="mi">50</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">25</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="n">a</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">stringtest</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">30</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="mi">31</span><span class="p">,</span> <span class="s2">" 0"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr90</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">31</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="s2">" 90"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr180</span><span class="p">(</span><span class="mi">30</span><span class="o">-</span><span class="n">a</span><span class="p">,</span> <span class="mi">31</span><span class="p">,</span> <span class="s2">" 180"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr270</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="mi">31</span><span class="o">-</span><span class="n">a</span><span class="p">,</span> <span class="s2">" 270"</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">line</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"drawLine"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawLine</span><span class="p">(</span><span class="mi">7</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">40</span><span class="p">,</span> <span class="mi">55</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawLine</span><span class="p">(</span><span class="mi">7</span><span class="o">+</span><span class="n">a</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">60</span><span class="p">,</span> <span class="mi">55</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawLine</span><span class="p">(</span><span class="mi">7</span><span class="o">+</span><span class="n">a</span><span class="o">*</span><span class="mi">3</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">80</span><span class="p">,</span> <span class="mi">55</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawLine</span><span class="p">(</span><span class="mi">7</span><span class="o">+</span><span class="n">a</span><span class="o">*</span><span class="mi">4</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">55</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">triangle</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">offset</span> <span class="o">=</span> <span class="n">a</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"drawTriangle"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawTriangle</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span> <span class="mi">45</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span><span class="mi">40</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawTriangle</span><span class="p">(</span><span class="mi">14</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span><span class="mi">7</span><span class="o">-</span><span class="n">offset</span><span class="p">,</span> <span class="mi">45</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span><span class="mi">30</span><span class="o">-</span><span class="n">offset</span><span class="p">,</span> <span class="mi">57</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span><span class="mi">10</span><span class="o">-</span><span class="n">offset</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawTriangle</span><span class="p">(</span><span class="mi">57</span><span class="o">+</span><span class="n">offset</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span><span class="mi">10</span><span class="p">,</span> <span class="mi">45</span><span class="o">+</span><span class="n">offset</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span><span class="mi">30</span><span class="p">,</span> <span class="mi">86</span><span class="o">+</span><span class="n">offset</span><span class="o">*</span><span class="mi">2</span><span class="p">,</span><span class="mi">53</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawTriangle</span><span class="p">(</span><span class="mi">10</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span><span class="mi">40</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span> <span class="mi">45</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span><span class="mi">30</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span> <span class="mi">86</span><span class="o">+</span><span class="n">offset</span><span class="p">,</span><span class="mi">53</span><span class="o">+</span><span class="n">offset</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">ascii_1</span><span class="p">()</span>
<span class="kd">local</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">s</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="s2">"ASCII page 1"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">y</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">1</span> <span class="k">do</span>
<span class="k">for</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">1</span> <span class="k">do</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">y</span><span class="o">*</span><span class="mi">16</span> <span class="o">+</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">32</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="n">x</span><span class="o">*</span><span class="mi">7</span><span class="p">,</span> <span class="n">y</span><span class="o">*</span><span class="mi">10</span><span class="o">+</span><span class="mi">10</span><span class="p">,</span> <span class="nb">string.char</span><span class="p">(</span><span class="n">s</span><span class="p">))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">extra_page</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="s2">"setScale2x2"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">setScale2x2</span><span class="p">()</span>
<span class="n">disp</span><span class="p">:</span><span class="n">drawStr</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">6</span><span class="o">+</span><span class="n">a</span><span class="p">,</span> <span class="s2">"setScale2x2"</span><span class="p">)</span>
<span class="n">disp</span><span class="p">:</span><span class="n">undoScale</span><span class="p">()</span>
<span class="k">end</span>
<span class="c1">-- the draw() routine</span>
<span class="k">function</span> <span class="nf">draw</span><span class="p">(</span><span class="n">draw_state</span><span class="p">)</span>
<span class="kd">local</span> <span class="n">component</span> <span class="o">=</span> <span class="n">bit</span><span class="p">.</span><span class="n">rshift</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">prepare</span><span class="p">()</span>
<span class="k">if</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">then</span>
<span class="n">box_frame</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="k">then</span>
<span class="n">disc_circle</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">2</span><span class="p">)</span> <span class="k">then</span>
<span class="n">r_frame</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="k">then</span>
<span class="n">stringtest</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="k">then</span>
<span class="n">line</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">5</span><span class="p">)</span> <span class="k">then</span>
<span class="n">triangle</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">6</span><span class="p">)</span> <span class="k">then</span>
<span class="n">ascii_1</span><span class="p">()</span>
<span class="k">elseif</span> <span class="p">(</span><span class="n">component</span> <span class="o">==</span> <span class="mi">7</span><span class="p">)</span> <span class="k">then</span>
<span class="n">extra_page</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">draw_state</span><span class="p">,</span> <span class="mi">7</span><span class="p">))</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">graphics_test</span><span class="p">()</span>
<span class="n">disp</span><span class="p">:</span><span class="n">firstPage</span><span class="p">()</span>
<span class="k">repeat</span>
<span class="n">draw</span><span class="p">(</span><span class="n">draw_state</span><span class="p">)</span>
<span class="k">until</span> <span class="n">disp</span><span class="p">:</span><span class="n">nextPage</span><span class="p">()</span> <span class="o">==</span> <span class="kc">false</span>
<span class="k">if</span> <span class="p">(</span><span class="n">draw_state</span> <span class="o"><=</span> <span class="mi">7</span> <span class="o">+</span> <span class="mi">8</span><span class="o">*</span><span class="mi">8</span><span class="p">)</span> <span class="k">then</span>
<span class="n">draw_state</span> <span class="o">=</span> <span class="n">draw_state</span> <span class="o">+</span> <span class="mi">1</span>
<span class="k">else</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"--- Restarting Graphics Test ---"</span><span class="p">)</span>
<span class="n">draw_state</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">end</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Heap: "</span> <span class="o">..</span> <span class="n">node</span><span class="p">.</span><span class="n">heap</span><span class="p">())</span>
<span class="c1">-- retrigger timer to give room for system housekeeping</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">draw_state</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1">--init_i2c_display()</span>
<span class="n">init_spi_display</span><span class="p">()</span>
<span class="c1">-- set up timer 0 with short interval, will be retriggered in graphics_test()</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">register</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="n">tmr</span><span class="p">.</span><span class="n">ALARM_SEMI</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="n">graphics_test</span><span class="p">()</span> <span class="k">end</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"--- Starting Graphics Test ---"</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></pre></td></tr></tbody></table></code></pre></figure>
<h2 id="result">Result</h2>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-oled-display-spi-final.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-oled-display-spi-final.jpg" alt="" class="lazyload fade-in" />
<figcaption>Running the U8G test program</figcaption>
</figure>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/1RrZqFnIecY?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<p>Everything works and from here it is just a matter on using the U8G library to show what you need. Take a look at the NodeMCU U8G documentation <a href="https://nodemcu.readthedocs.org/en/dev/en/modules/u8g/">here</a>.</p>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-nodemcu-oled-display-spi/" rel="nofollow">ESP8266 NodeMCU - OLED display using SPI</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/ESP8266 NodeMCU - OLED display using SPIESP8266 Controlling an IHC wireless light switch2016-04-10T00:00:00+00:002016-04-09T22:00:47+00:00https://odd-one-out.serek.eu/projects/esp8266-nodemcu-ihc-wireless-webserver-light-switch
<p><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-feature.jpg" alt="" /></p>
<p>Recently I installed several intelligent IHC Wireless lightswitches and power outlets from Lauritz Knudsen. They can be programmed so that any switch can wirelessly control any other switch or power outlet. I wanted to control these switches using my phone and was left with three options</p>
<ol>
<li>Buy an IHC Wireless Controller for around $750 and try to integrate an ESP8266 to control the switches</li>
<li>Try to hack the proprietary IHC Wireless protocol and send the commands directly to the switches using an ESP8266 and a radio transceiver module</li>
<li>Modify an IHC Wireless switch so that an ESP8266 can control the buttons directly</li>
</ol>
<p>Option 1 is too expensive for what I want to do and as far as I know nobody has been able to hack the protocol in option 2. So that left option 3!
I bought a battery powered IHC Wireless switch with a total of 7 buttons. Each lightswitch has one on and one off button. The last button is used to program the switch. This was the cheapest option at around $75. Next I took the switch apart and saw it was a simple matter to activate the 7 small buttons.</p>
<figure class="gallery-3-col">
<a href="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-front.jpg"><noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-front.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-front.jpg" alt="IHC Wireless battery powered switch" class="lazyload fade-in" /></a>
<a href="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-without-button-panels.jpg"><noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-without-button-panels.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-without-button-panels.jpg" alt="IHC Wireless battery powered switch with the button panels taken off" class="lazyload fade-in" /></a>
<a href="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-internal.jpg"><noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-internal.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-internal.jpg" alt="IHC Wireless battery powered switch with the front panel off" class="lazyload fade-in" /></a>
<figcaption>IHC Wireless battery powered switch, here shown fully assembled, with the button panels of and with the front cover off</figcaption>
</figure>
<p>Next I hooked up and ESP8266 development board, a few BC547B transistors, 10K resistors and wires and that was it for the hardware setup.</p>
<figure class="gallery-2-col">
<a href="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-working-prototype.jpg"><noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-working-prototype.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-working-prototype.jpg" alt="ESP8266 development board controlling button 1 and 2 of the IHC Wireless switch" class="lazyload fade-in" /></a>
<a href="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-working-prototype-closeup.jpg"><noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-working-prototype-closeup.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-working-prototype-closeup.jpg" alt="ESP8266 development board controlling button 1 and 2 of the IHC Wireless switch – closeup" class="lazyload fade-in" /></a>
<figcaption>ESP8266 development board controlling button 1 and 2 of the IHC Wireless switch</figcaption>
</figure>
<p>Notice that I have only hooked up two buttons, but the webserver supports up to 7 buttons</p>
<h2 id="parts">Parts</h2>
<p>If you don’t mind waiting a few weeks I would recommend buying from AliExpress as I have done for the lowest price and free shipping, even to Europe! I cannot recommend Amazon for parts like these since they are very expensive even with free shipping from Amazon Prime. I have created a table to compare the prices so that people can make up their own mind.</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<table>
<thead>
<tr>
<th>Part</th>
<th>Ali Express</th>
<th>Amazon</th>
</tr>
</thead>
<tbody>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B010O1G1ES/" rel="nofollow" data-amazon-asin="[us]B010O1G1ES[ca]B019FBLEYU[uk]B010N1SPRK[de]B0182JOWOK[es][it][fr]">ESP8266 development board</a></td>
<td><a href="https://www.aliexpress.com/item/V2-4M-4FLASH-NodeMcu-Lua-WIFI-Networking-development-board-Based-ESP8266/32448662166.html" rel="nofollow">$4.2</a></td>
<td><a href="https://www.amazon.com/dp/B010O1G1ES/" rel="nofollow" data-amazon-asin="[us]B010O1G1ES[ca]B019FBLEYU[uk]B010N1SPRK[de]B0182JOWOK[es][it][fr]">$9</a></td>
</tr>
<tr>
<td>1x <a href="http://www.wattoo.dk/lk-ihc-wireless-batteritryk-lk-fuga-6-slutte-hvid-1092001540" rel="nofollow">IHC Wireless switch</a></td>
<td>N/A</td>
<td>N/A</td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B0084A7PI8/" rel="nofollow" data-amazon-asin="[us][ca][es]B0084A7PI8[uk][de]B00JGFDKBQ[it][fr]B00PQC72ZS">breadboard</a></td>
<td><a href="https://www.aliexpress.com/item/1pcs-Quality-mini-bread-board-breadboard-8-5CM-x-5-5CM-400-holes-For-expansion-arduino/1906352269.html" rel="nofollow">$1.2</a></td>
<td><a href="https://www.amazon.com/dp/B0084A7PI8/" rel="nofollow" data-amazon-asin="[us][ca][es]B0084A7PI8[uk][de]B00JGFDKBQ[it][fr]B00PQC72ZS">$5.2</a></td>
</tr>
<tr>
<td>1-7x <a href="https://www.amazon.com/dp/B00B5RJF1M/" rel="nofollow" data-amazon-asin="[us]B00B5RJF1M[ca]B0087ZDSV8[uk]B004S0XA1O[de]B00IYUWT2A[es][it][fr]">10K resistor</a> (one for each button you want to control)</td>
<td><a href="https://www.aliexpress.com/item/100pcs-10k-ohm-1-4W-10k-Metal-Film-Resistor-10kohm-0-25W-1-ROHS/32577051768.html" rel="nofollow">$0.7</a></td>
<td><a href="https://www.amazon.com/dp/B00B5RJF1M/" rel="nofollow" data-amazon-asin="[us]B00B5RJF1M[ca]B0087ZDSV8[uk]B004S0XA1O[de]B00IYUWT2A[es][it][fr]">$4.9</a></td>
</tr>
<tr>
<td>1-7x <a href="https://www.amazon.com/dp/B00CHTOVU2/" rel="nofollow" data-amazon-asin="[us]B00CHTOVU2[ca]B01BT93MY6[uk]B00UB2YS5U[de][it][fr]B00Q6WQ14K[es]B01M3R5GE8">BC547B transistor</a> (one for each button you want to control)</td>
<td><a href="https://www.aliexpress.com/item/FREE-SHIPPING-50PCS-BC547B-BC547-TO-92-TO92-DIP-NPN-general-purpose-transistors/32328944159.html" rel="nofollow">$1.1</a></td>
<td><a href="https://www.amazon.com/dp/B00CHTOVU2/" rel="nofollow" data-amazon-asin="[us]B00CHTOVU2[ca]B01BT93MY6[uk]B00UB2YS5U[de][it][fr]B00Q6WQ14K[es]B01M3R5GE8">$5.5</a></td>
</tr>
<tr>
<td><a href="https://www.amazon.com/dp/B014JOV4TI/" rel="nofollow" data-amazon-asin="[us]B014JOV4TI[ca]B0002H7AIQ[uk]B01B7M5S6K[de]B01B4HO30K[es]B01GQOJY7I[it]B01GZ2LP82[fr]B01IX7WMAM">Various breadboard wires</a></td>
<td><a href="https://www.aliexpress.com/af/breadboard%25252dwires.html?SearchText=breadboard+wires&blanktest=0&origin=n&jump=afs" rel="nofollow">$2.6</a></td>
<td><a href="https://www.amazon.com/dp/B014JOV4TI/" rel="nofollow" data-amazon-asin="[us]B014JOV4TI[ca]B0002H7AIQ[uk]B01B7M5S6K[de]B01B4HO30K[es]B01GQOJY7I[it]B01GZ2LP82[fr]B01IX7WMAM">$5.9</a></td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$84.8</td>
<td>$105.5</td>
</tr>
<tr>
<td><strong>Total without IHC Wireless switch</strong></td>
<td>$9.8</td>
<td>$30.5</td>
</tr>
</tbody>
</table>
<h2 id="hardware-setup">Hardware setup</h2>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-fritzing.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-fritzing.png" alt="" class="lazyload fade-in" />
<figcaption>Hardware setup</figcaption>
</figure>
<p>The two buttons connected by the yellow wires are from the IHC Wireless switch. Other than that the setup is straight forward.</p>
<h2 id="code">Code</h2>
<p>Upload the following code as <code class="highlighter-rouge">init.lua</code> to your ESP8266. If you don’t know how, take a look at my post <a href="/projects/esp8266-nodemcu-getting-started-hello-world/">here</a>. The most important parameters to configure are:</p>
<ul>
<li><code class="highlighter-rouge">switch*_pin</code>: Map up to 7 switches to the GPIO of the ESP8266</li>
<li><code class="highlighter-rouge">wifi_SSID</code>: Wifi name</li>
<li><code class="highlighter-rouge">wifi_password</code>: Wifi password</li>
<li><code class="highlighter-rouge">client_*</code>: Optionally set a static ip address, netmask and gateway. If <code class="highlighter-rouge">client_ip</code> is not set, DHCP will be used</li>
</ul>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
</pre></td><td class="code"><pre><span class="c1">-- Webserver to control several on / off switches.</span>
<span class="c1">-- Idea inspired by: https://www.youtube.com/watch?v=DPVmGG4xifU</span>
<span class="c1">-- HTML inspired by: https://github.com/mrkale/NodeMCU-WifiDoubleSwitch</span>
<span class="c1">-- Config</span>
<span class="n">switch1_pin</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1">-- Room 1 On</span>
<span class="n">switch2_pin</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1">-- Room 1 Off</span>
<span class="n">switch3_pin</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1">-- Room 2 On</span>
<span class="n">switch4_pin</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1">-- Room 2 Off</span>
<span class="n">switch5_pin</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1">-- Room 3 On</span>
<span class="n">switch6_pin</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1">-- Room 3 Off</span>
<span class="n">switch7_pin</span> <span class="o">=</span> <span class="mi">3</span> <span class="c1">-- Programmable switch</span>
<span class="c1">--- WIFI ---</span>
<span class="n">wifi_SSID</span> <span class="o">=</span> <span class="s2">"wifi_name"</span>
<span class="n">wifi_password</span> <span class="o">=</span> <span class="s2">"wifi_password"</span>
<span class="c1">-- wifi.PHYMODE_B 802.11b, More range, Low Transfer rate, More current draw</span>
<span class="c1">-- wifi.PHYMODE_G 802.11g, Medium range, Medium transfer rate, Medium current draw</span>
<span class="c1">-- wifi.PHYMODE_N 802.11n, Least range, Fast transfer rate, Least current draw</span>
<span class="n">wifi_signal_mode</span> <span class="o">=</span> <span class="n">wifi</span><span class="p">.</span><span class="n">PHYMODE_N</span>
<span class="c1">-- If the settings below are filled out then the module connects</span>
<span class="c1">-- using a static ip address which is faster than DHCP and</span>
<span class="c1">-- better for battery life. Blank "" will use DHCP.</span>
<span class="c1">-- My own tests show around 1-2 seconds with static ip</span>
<span class="c1">-- and 4+ seconds for DHCP</span>
<span class="n">client_ip</span><span class="o">=</span><span class="s2">"192.168.1.111"</span>
<span class="n">client_netmask</span><span class="o">=</span><span class="s2">"255.255.255.0"</span>
<span class="n">client_gateway</span><span class="o">=</span><span class="s2">"192.168.1.1"</span>
<span class="c1">-- Connect to the wifi network</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">wifi</span><span class="p">.</span><span class="n">STATION</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setphymode</span><span class="p">(</span><span class="n">wifi_signal_mode</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">config</span><span class="p">(</span><span class="n">wifi_SSID</span><span class="p">,</span> <span class="n">wifi_password</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">connect</span><span class="p">()</span>
<span class="k">if</span> <span class="n">client_ip</span> <span class="o">~=</span> <span class="s2">""</span> <span class="k">then</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">setip</span><span class="p">({</span><span class="n">ip</span><span class="o">=</span><span class="n">client_ip</span><span class="p">,</span><span class="n">netmask</span><span class="o">=</span><span class="n">client_netmask</span><span class="p">,</span><span class="n">gateway</span><span class="o">=</span><span class="n">client_gateway</span><span class="p">})</span>
<span class="k">end</span>
<span class="c1">-- Connect</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span>
<span class="k">if</span> <span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">getip</span><span class="p">()</span> <span class="o">==</span> <span class="kc">nil</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Connecting to AP...\n"</span><span class="p">)</span>
<span class="k">else</span>
<span class="n">ip</span><span class="p">,</span> <span class="n">nm</span><span class="p">,</span> <span class="n">gw</span><span class="o">=</span><span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">getip</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"IP address: "</span><span class="p">,</span><span class="n">ip</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">stop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch1_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch2_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch3_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch4_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch5_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch6_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">switch7_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch1_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch2_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch3_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch4_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch5_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch6_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">switch7_pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">stop</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="c1">-- Start a simple http server</span>
<span class="n">srv</span><span class="o">=</span><span class="n">net</span><span class="p">.</span><span class="n">createServer</span><span class="p">(</span><span class="n">net</span><span class="p">.</span><span class="n">TCP</span><span class="p">)</span>
<span class="n">srv</span><span class="p">:</span><span class="n">listen</span><span class="p">(</span><span class="mi">80</span><span class="p">,</span><span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">on</span><span class="p">(</span><span class="s2">"receive"</span><span class="p">,</span><span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span><span class="n">request</span><span class="p">)</span>
<span class="c1">-- https://github.com/marcoskirsch/nodemcu-httpserver/issues/36#issuecomment-167442461</span>
<span class="c1">-- Some browsers send the POST data in multiple chunks, like Safari on OS X and IOS</span>
<span class="c1">-- Collect data packets until the size of HTTP body meets the Content-Length stated in header</span>
<span class="c1">-- This fixed issues where the webpage was rendered twice after posting data to the server in some browsers</span>
<span class="k">if</span> <span class="n">request</span><span class="p">:</span><span class="n">find</span><span class="p">(</span><span class="s2">"Content%-Length:"</span><span class="p">)</span> <span class="ow">or</span> <span class="n">bBodyMissing</span> <span class="k">then</span>
<span class="k">if</span> <span class="n">fullPayload</span> <span class="k">then</span> <span class="n">fullPayload</span> <span class="o">=</span> <span class="n">fullPayload</span> <span class="o">..</span> <span class="n">request</span> <span class="k">else</span> <span class="n">fullPayload</span> <span class="o">=</span> <span class="n">request</span> <span class="k">end</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">tonumber</span><span class="p">(</span><span class="nb">string.match</span><span class="p">(</span><span class="n">fullPayload</span><span class="p">,</span> <span class="s2">"%d+"</span><span class="p">,</span> <span class="n">fullPayload</span><span class="p">:</span><span class="n">find</span><span class="p">(</span><span class="s2">"Content%-Length:"</span><span class="p">)</span><span class="o">+</span><span class="mi">16</span><span class="p">))</span> <span class="o">></span> <span class="o">#</span><span class="n">fullPayload</span><span class="p">:</span><span class="n">sub</span><span class="p">(</span><span class="n">fullPayload</span><span class="p">:</span><span class="n">find</span><span class="p">(</span><span class="s2">"</span><span class="se">\r\n\r\n</span><span class="s2">"</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="kc">true</span><span class="p">)</span><span class="o">+</span><span class="mi">4</span><span class="p">,</span> <span class="o">#</span><span class="n">fullPayload</span><span class="p">))</span> <span class="k">then</span>
<span class="n">bBodyMissing</span> <span class="o">=</span> <span class="kc">true</span>
<span class="k">return</span>
<span class="k">else</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"HTTP packet assembled! size: "</span><span class="o">..#</span><span class="n">fullPayload</span><span class="p">)</span>
<span class="n">request</span> <span class="o">=</span> <span class="n">fullPayload</span>
<span class="n">fullPayload</span><span class="p">,</span> <span class="n">bBodyMissing</span> <span class="o">=</span> <span class="kc">nil</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="c1">-- Handle POST request - switching on and off the various switches</span>
<span class="n">_</span><span class="p">,</span> <span class="n">j</span> <span class="o">=</span> <span class="nb">string.find</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'switch='</span><span class="p">)</span>
<span class="k">if</span> <span class="n">j</span> <span class="o">~=</span> <span class="kc">nil</span> <span class="k">then</span>
<span class="n">command</span> <span class="o">=</span> <span class="nb">string.sub</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Switch "</span><span class="o">..</span><span class="n">command</span><span class="o">..</span><span class="s2">" click"</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="nb">tonumber</span><span class="p">(</span><span class="n">command</span><span class="p">),</span> <span class="n">gpio</span><span class="p">.</span><span class="n">HIGH</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">start</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1">-- Reponse HTTP headers</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s2">"HTTP/1.1 200 OK\r\n"</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s2">"Content-Type: text/html\r\n"</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s2">"Connection: keep-alive\r\n\r\n"</span><span class="p">)</span>
<span class="c1">-- HTML response</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">'<!DOCTYPE html>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">'<html lang="en">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <head>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <meta charset="utf-8" />'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <title>IHC Wireless</title>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <meta http-equiv="X-UA-Compatible" content="IE=edge">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <meta name="viewport" content="width=device-width, initial-scale=1">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </head>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <body>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <h1 class="hidden-xs text-center">IHC Wireless</h1>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <form method="post">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="container">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="row">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="col-sm-4 col-sm-offset-0">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <h3 class="text-primary text-center">Kitchen</h3>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-success" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch1_pin</span><span class="o">..</span><span class="s1">'">On</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-danger" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch2_pin</span><span class="o">..</span><span class="s1">'">Off</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="col-sm-4 col-sm-offset-0">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <h3 class="text-primary text-center">Living room</h3>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-success" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch3_pin</span><span class="o">..</span><span class="s1">'">On</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-danger" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch4_pin</span><span class="o">..</span><span class="s1">'">Off</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="col-sm-4 col-sm-offset-0">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <h3 class="text-primary text-center">Bedroom</h3>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-success" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch5_pin</span><span class="o">..</span><span class="s1">'">On</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-danger" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch6_pin</span><span class="o">..</span><span class="s1">'">Off</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="row">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <div class="col-sm-4 col-sm-offset-4">'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <h3 class="text-primary text-center">Setup</h3>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' <button class="btn btn-block btn-lg btn-warning" role="button" type="submit" name="switch" value="'</span><span class="o">..</span><span class="n">switch7_pin</span><span class="o">..</span><span class="s1">'">Program</>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </div>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </form>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">' </body>'</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">send</span><span class="p">(</span><span class="s1">'</html>'</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">on</span><span class="p">(</span><span class="s2">"sent"</span><span class="p">,</span><span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="n">conn</span><span class="p">:</span><span class="n">close</span><span class="p">()</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span></pre></td></tr></tbody></table></code></pre></figure>
<h2 id="results">Results</h2>
<p>With all connected and up and running, the browser should be accessible from the IP address specified in <code class="highlighter-rouge">client_ip</code> or assigned from DHCP. The site is fully responsive so it looks nice on any device.</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-desktop-browser.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-desktop-browser.png" alt="" class="lazyload fade-in" />
<figcaption>Desktop browser</figcaption>
</figure>
<figure class="gallery-2-col center">
<noscript><img src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-mobile-browser.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-ihc-wireless-webserver-light-switch-mobile-browser.png" alt="" class="lazyload fade-in" />
<figcaption>Mobile device</figcaption>
</figure>
<p>And the most important part, it actually works!</p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/2Lpl3N411eA?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<p>Connecting to the ESP8266 using the serial ports shows the following output:</p>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="go">NodeMCU custom build by frightanic.com
branch: dev
commit: 093a895980fbd4ab8b3ebedcd6efe36e26419887
SSL: true
modules: node,file,gpio,wifi,net,tmr,adc,mqtt,dht
built on: 2015-10-13 18:26
powered by Lua 5.1.4
</span><span class="gp">></span> IP address: 192.168.1.111
<span class="go">Switch 1 click
Switch 2 click</span></code></pre></figure>
<h2 id="whats-next">Whats next?</h2>
<ul>
<li>Hook up the remaining buttons to the ESP8266</li>
<li>Solder all the wires and hide the whole thing in a case</li>
<li>Power the IHC Wireless switch using the ESP8266. It currently uses an 3V CR2022 coin cell battery and the ESP8266 development board uses 3.3V so it should be possible</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-nodemcu-ihc-wireless-webserver-light-switch/" rel="nofollow">ESP8266 Controlling an IHC wireless light switch</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/ESP8266 Controlling an IHC wireless light switchESP8266 NodeMCU - DHT22 sensor and ThingSpeak2016-03-19T00:00:00+00:002016-03-19T18:01:02+00:00https://odd-one-out.serek.eu/projects/esp8266-nodemcu-dht22-thingspeak
<p><img src="/assets/images/esp8266-nodemcu-dht22-thingspeak-feature.png" alt="" /></p>
<p>I have previously <a href="/projects/esp8266-nodemcu-dht22-mqtt-deep-sleep/">written</a> about pushing temperature and humidity readings from an ESP8266 to a MQTT server using a DHT22 sensor. Later I <a href="/projects/esp8266-nodemcu-dht22-custom-modules-firmware/">leveraged</a> NodeMCU’s built-in DHT22 library by using an online <a href="http://nodemcu-build.com">service</a> to create a streamlined NodeMCU firmware fit for my needs. However, a reader asked me about pushing data to <a href="http://thingspeak.com">ThingSpeak.com</a> instead and here is the reply.</p>
<h2 id="hardware">Hardware</h2>
<p>Follow my post <a href="/projects/esp8266-nodemcu-dht22-mqtt-deep-sleep/">here</a> on how to connect all the parts.</p>
<h2 id="nodemcu-firmware">NodeMCU firmware</h2>
<p>Follow my post <a href="/projects/esp8266-nodemcu-dht22-custom-modules-firmware/">here</a> on how to built a custom NodeMCU firmware and remember to check the DHT library. If you need help flashing the firmware you can take a look at my guide <a href="/proejcts/esp8266-development-kit-nodemcu-firmware-update-os-x/">here</a>.</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-dht22-thingspeak-nodemcu-build.com-DHT.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-dht22-thingspeak-nodemcu-build.com-DHT.png" alt="" class="lazyload fade-in" />
<figcaption>Nodemcu-build.com default values and DHT selected</figcaption>
</figure>
<h2 id="software">Software</h2>
<p>Instead of the test code described in my post <a href="/projects/esp8266-nodemcu-dht22-custom-modules-firmware/">here</a>, use the one below. Configure the following variables before uploading to the ESP8266:</p>
<ul>
<li><code class="highlighter-rouge">thingspeak_channel_api_write_key</code></li>
<li><code class="highlighter-rouge">thingspeak_temperature_field_name</code></li>
<li><code class="highlighter-rouge">thingspeak_humidity_field_name</code></li>
<li><code class="highlighter-rouge">wifi_SSID</code></li>
<li><code class="highlighter-rouge">wifi_password</code></li>
</ul>
<p>And I recommend to use a static IP address for faster connection times, just set the <code class="highlighter-rouge">client_*</code> variables.</p>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
</pre></td><td class="code"><pre><span class="c1">-- Thingspeak connect script with deep sleep</span>
<span class="c1">-- Remember to connect GPIO16 and RST to enable deep sleep</span>
<span class="c1">-- TODO: Log error codes to server</span>
<span class="c1">--############</span>
<span class="c1">--# Settings #</span>
<span class="c1">--############</span>
<span class="c1">--- Thingspeak ---</span>
<span class="n">thingspeak_channel_api_write_key</span> <span class="o">=</span> <span class="s2">"LU1TXYV15GBVTDHU"</span>
<span class="n">thingspeak_temperature_field_name</span> <span class="o">=</span> <span class="s2">"field1"</span>
<span class="n">thingspeak_humidity_field_name</span> <span class="o">=</span> <span class="s2">"field2"</span>
<span class="c1">--- WIFI ---</span>
<span class="n">wifi_SSID</span> <span class="o">=</span> <span class="s2">"wifi-Name"</span>
<span class="n">wifi_password</span> <span class="o">=</span> <span class="s2">"wifi-Password"</span>
<span class="c1">-- wifi.PHYMODE_B 802.11b, More range, Low Transfer rate, More current draw</span>
<span class="c1">-- wifi.PHYMODE_G 802.11g, Medium range, Medium transfer rate, Medium current draw</span>
<span class="c1">-- wifi.PHYMODE_N 802.11n, Least range, Fast transfer rate, Least current draw</span>
<span class="n">wifi_signal_mode</span> <span class="o">=</span> <span class="n">wifi</span><span class="p">.</span><span class="n">PHYMODE_N</span>
<span class="c1">-- If the settings below are filled out then the module connects</span>
<span class="c1">-- using a static ip address which is faster than DHCP and</span>
<span class="c1">-- better for battery life. Blank "" will use DHCP.</span>
<span class="c1">-- My own tests show around 1-2 seconds with static ip</span>
<span class="c1">-- and 4+ seconds for DHCP</span>
<span class="n">client_ip</span><span class="o">=</span><span class="s2">""</span>
<span class="n">client_netmask</span><span class="o">=</span><span class="s2">""</span>
<span class="n">client_gateway</span><span class="o">=</span><span class="s2">""</span>
<span class="c1">--- INTERVAL ---</span>
<span class="c1">-- In milliseconds. Remember that the sensor reading,</span>
<span class="c1">-- reboot and wifi reconnect takes a few seconds</span>
<span class="n">time_between_sensor_readings</span> <span class="o">=</span> <span class="mi">60000</span>
<span class="c1">--################</span>
<span class="c1">--# END settings #</span>
<span class="c1">--################</span>
<span class="n">temperature</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">humidity</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1">-- Connect to the wifi network</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">wifi</span><span class="p">.</span><span class="n">STATION</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setphymode</span><span class="p">(</span><span class="n">wifi_signal_mode</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">config</span><span class="p">(</span><span class="n">wifi_SSID</span><span class="p">,</span> <span class="n">wifi_password</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">connect</span><span class="p">()</span>
<span class="k">if</span> <span class="n">client_ip</span> <span class="o">~=</span> <span class="s2">""</span> <span class="k">then</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">setip</span><span class="p">({</span><span class="n">ip</span><span class="o">=</span><span class="n">client_ip</span><span class="p">,</span><span class="n">netmask</span><span class="o">=</span><span class="n">client_netmask</span><span class="p">,</span><span class="n">gateway</span><span class="o">=</span><span class="n">client_gateway</span><span class="p">})</span>
<span class="k">end</span>
<span class="c1">-- DHT22 sensor logic</span>
<span class="k">function</span> <span class="nf">get_sensor_Data</span><span class="p">()</span>
<span class="n">dht</span><span class="o">=</span><span class="nb">require</span><span class="p">(</span><span class="s2">"dht"</span><span class="p">)</span>
<span class="n">status</span><span class="p">,</span><span class="n">temp</span><span class="p">,</span><span class="n">humi</span><span class="p">,</span><span class="n">temp_decimial</span><span class="p">,</span><span class="n">humi_decimial</span> <span class="o">=</span> <span class="n">dht</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">if</span><span class="p">(</span> <span class="n">status</span> <span class="o">==</span> <span class="n">dht</span><span class="p">.</span><span class="n">OK</span> <span class="p">)</span> <span class="k">then</span>
<span class="c1">-- Prevent "0.-2 deg C" or "-2.-6" </span>
<span class="n">temperature</span> <span class="o">=</span> <span class="n">temp</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="nb">math.abs</span><span class="p">(</span><span class="n">temp_decimial</span><span class="p">)</span><span class="o">/</span><span class="mi">100</span><span class="p">)</span>
<span class="n">humidity</span> <span class="o">=</span> <span class="n">humi</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="nb">math.abs</span><span class="p">(</span><span class="n">humi_decimial</span><span class="p">)</span><span class="o">/</span><span class="mi">100</span><span class="p">)</span>
<span class="c1">-- If temp is zero and temp_decimal is negative, then add "-" to the temperature string</span>
<span class="k">if</span><span class="p">(</span><span class="n">temp</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">temp_decimial</span><span class="o"><</span><span class="mi">0</span><span class="p">)</span> <span class="k">then</span>
<span class="n">temperature</span> <span class="o">=</span> <span class="s2">"-"</span><span class="o">..</span><span class="n">temperature</span>
<span class="k">end</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Temperature: "</span><span class="o">..</span><span class="n">temperature</span><span class="o">..</span><span class="s2">" deg C"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Humidity: "</span><span class="o">..</span><span class="n">humidity</span><span class="o">..</span><span class="s2">"%"</span><span class="p">)</span>
<span class="k">elseif</span><span class="p">(</span> <span class="n">status</span> <span class="o">==</span> <span class="n">dht</span><span class="p">.</span><span class="n">ERROR_CHECKSUM</span> <span class="p">)</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span> <span class="s2">"DHT Checksum error"</span> <span class="p">)</span>
<span class="n">temperature</span><span class="o">=-</span><span class="mi">1</span> <span class="c1">--TEST</span>
<span class="k">elseif</span><span class="p">(</span> <span class="n">status</span> <span class="o">==</span> <span class="n">dht</span><span class="p">.</span><span class="n">ERROR_TIMEOUT</span> <span class="p">)</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span> <span class="s2">"DHT Time out"</span> <span class="p">)</span>
<span class="n">temperature</span><span class="o">=-</span><span class="mi">2</span> <span class="c1">--TEST</span>
<span class="k">end</span>
<span class="c1">-- Release module</span>
<span class="n">dht</span><span class="o">=</span><span class="kc">nil</span>
<span class="nb">package.loaded</span><span class="p">[</span><span class="s2">"dht"</span><span class="p">]</span><span class="o">=</span><span class="kc">nil</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">loop</span><span class="p">()</span>
<span class="k">if</span> <span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">status</span><span class="p">()</span> <span class="o">==</span> <span class="mi">5</span> <span class="k">then</span>
<span class="c1">-- Stop the loop</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">stop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">con</span> <span class="o">=</span> <span class="kc">nil</span>
<span class="n">con</span> <span class="o">=</span> <span class="n">net</span><span class="p">.</span><span class="n">createConnection</span><span class="p">(</span><span class="n">net</span><span class="p">.</span><span class="n">TCP</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">con</span><span class="p">:</span><span class="n">on</span><span class="p">(</span><span class="s2">"receive"</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">con</span><span class="p">,</span> <span class="n">payloadout</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">string.find</span><span class="p">(</span><span class="n">payloadout</span><span class="p">,</span> <span class="s2">"Status: 200 OK"</span><span class="p">)</span> <span class="o">~=</span> <span class="kc">nil</span><span class="p">)</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Posted OK to ThingSpeak"</span><span class="p">);</span>
<span class="k">end</span>
<span class="k">end</span><span class="p">)</span>
<span class="n">con</span><span class="p">:</span><span class="n">on</span><span class="p">(</span><span class="s2">"connection"</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">con</span><span class="p">,</span> <span class="n">payloadout</span><span class="p">)</span>
<span class="c1">-- Get sensor data</span>
<span class="n">get_sensor_Data</span><span class="p">()</span>
<span class="c1">-- Post data to Thingspeak</span>
<span class="n">con</span><span class="p">:</span><span class="n">send</span><span class="p">(</span>
<span class="s2">"POST /update?api_key="</span> <span class="o">..</span> <span class="n">thingspeak_channel_api_write_key</span> <span class="o">..</span>
<span class="s2">"&field1="</span> <span class="o">..</span> <span class="n">temperature</span> <span class="o">..</span>
<span class="s2">"&field2="</span> <span class="o">..</span> <span class="n">humidity</span> <span class="o">..</span>
<span class="s2">" HTTP/1.1\r\n"</span> <span class="o">..</span>
<span class="s2">"Host: api.thingspeak.com\r\n"</span> <span class="o">..</span>
<span class="s2">"Connection: close\r\n"</span> <span class="o">..</span>
<span class="s2">"Accept: */*\r\n"</span> <span class="o">..</span>
<span class="s2">"User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n"</span> <span class="o">..</span>
<span class="s2">"</span><span class="se">\r\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="n">con</span><span class="p">:</span><span class="n">on</span><span class="p">(</span><span class="s2">"disconnection"</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">con</span><span class="p">,</span> <span class="n">payloadout</span><span class="p">)</span>
<span class="n">con</span><span class="p">:</span><span class="n">close</span><span class="p">();</span>
<span class="nb">collectgarbage</span><span class="p">();</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Going to deep sleep for "</span><span class="o">..</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">/</span><span class="mi">1000</span><span class="p">)</span><span class="o">..</span><span class="s2">" seconds"</span><span class="p">)</span>
<span class="n">node</span><span class="p">.</span><span class="n">dsleep</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="c1">-- Connect to Thingspeak</span>
<span class="n">con</span><span class="p">:</span><span class="n">connect</span><span class="p">(</span><span class="mi">80</span><span class="p">,</span><span class="s1">'api.thingspeak.com'</span><span class="p">)</span>
<span class="k">else</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Connecting..."</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="n">loop</span><span class="p">()</span> <span class="k">end</span><span class="p">)</span>
<span class="c1">-- Watchdog loop, will force deep sleep the operation somehow takes too long</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">4000</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="k">function</span><span class="p">()</span> <span class="n">node</span><span class="p">.</span><span class="n">dsleep</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span> <span class="k">end</span><span class="p">)</span></pre></td></tr></tbody></table></code></pre></figure>
<h2 id="result">Result</h2>
<p>If everything went well you should see the following repeated every 60 seconds on your ESP8266:</p>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="go">NodeMCU custom build by frightanic.com
branch: dev
commit: 093a895980fbd4ab8b3ebedcd6efe36e26419887
SSL: true
modules: node,file,gpio,wifi,net,tmr,adc,dht
built on: 2015-10-13 18:26
powered by Lua 5.1.4
</span><span class="gp">></span> Connecting...
<span class="go">Temperature: 23.2 deg C
Humidity: 39.1%
Posted OK to ThingSpeak
Going to deep sleep for 60 seconds</span></code></pre></figure>
<p>The results should now show up right away at your ThingSpeak channel.</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-dht22-thingspeak-feature.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-dht22-thingspeak-feature.png" alt="" class="lazyload fade-in" />
<figcaption>Thingspeak with temperature and humidity data from and ESP8266 using a DHT22 sensor</figcaption>
</figure>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-nodemcu-dht22-thingspeak/" rel="nofollow">ESP8266 NodeMCU - DHT22 sensor and ThingSpeak</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/ESP8266 NodeMCU - DHT22 sensor and ThingSpeakBullitt cargo bike with solar panels2016-03-13T00:00:00+00:002016-03-13T20:30:13+00:00https://odd-one-out.serek.eu/projects/bullitt-cargo-bike-voltaic-solar-panels
<p><img src="/assets/images/bullitt-cargo-bike-voltaic-solar-panels-Voltaic-Arc-20W-Fuse-10W-feature.jpg" alt="" /></p>
<p>I finally became a proper citizen of Copenhagen, Denmark… I bought a cargo bicycle! Now this isn’t any old cargo bike, it is a new take on the Danish Long John from 1923. Introducing the <a href="http://larryvsharry.com">Bullitt</a> from Larry vs Harry with a load capacity of 180 kilo, driver included. Now with all that room and capacity it is time to take my geeky projects outside and enjoy the weather!</p>
<figure>
<noscript><img src="/assets/images/bullitt-cargo-bike-voltaic-solar-panels-Bullitt.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/bullitt-cargo-bike-voltaic-solar-panels-Bullitt.jpg" alt="" class="lazyload fade-in" />
<figcaption>My Bullitt cargo bike in Copenhagen, loaded up with a few Voltaic solar panels.</figcaption>
</figure>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<p>One thing I needed was a renewable source of energy so I bought a front wheel dynamo, the <a href="https://www.amazon.com/dp/B007M817QE/" rel="nofollow" data-amazon-asin="[de]B015HBDJ6I[uk]B007HIJTSC[us]B007M817QE[ca]B002J9CCUG">Shimano DH-S501 Alfine Dynamo Disc Hub</a>, which generates about 3 watts of power at 6v AC. This can output about 0.5 amps at 5v DC using an adapter to charge USB devices, but it is a bit on the low side. It also introduces some drag as you can see from the video, but nothing I can feel when using the bike.</p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/u-06EIBJo3Y?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<p>So I decided to mount my Voltaic solar panels for a total of 30 watts of pure solar power!</p>
<figure>
<noscript><img src="/assets/images/bullitt-cargo-bike-voltaic-solar-panels-Voltaic-Arc-20W-Fuse-10W.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/bullitt-cargo-bike-voltaic-solar-panels-Voltaic-Arc-20W-Fuse-10W.jpg" alt="" class="lazyload fade-in" />
<figcaption>Bullitt cargo bike with Voltaic Arc 20W and Fuse 10W solar panels mounted. The charging is done using a 16.000 mAh Voltaic V60 battery.</figcaption>
</figure>
<p>The setup consists of</p>
<ul>
<li><a href="https://www.amazon.ca/dp/B006L4F2P2/" rel="nofollow" data-amazon-asin="[us]ca[de][uk][es][it][fr][ca]B006L4F2P2">Voltaic Fuse 10W solar panel</a>. This also doubles up as a bag with easy access to the battery, adapters and cables for charging</li>
<li><a href="https://www.amazon.com/dp/B002W9ICWA/" rel="nofollow" data-amazon-asin="[us]B002W9ICWA">Voltaic Arc 20W foldable solar panel</a></li>
<li><a href="https://www.amazon.com/dp/B006L4IP3I/" rel="nofollow" data-amazon-asin="[de][us]B006L4IP3I">Voltaic V60 16.000 mAh battery</a>. You might want to get the newer <a href="https://www.amazon.ca/dp/B00ISH4WEW/" rel="nofollow" data-amazon-asin="[us]ca[uk][ca]B00ISH4WEW">V72 battery</a> which has a capacity of 20.000 mAh.</li>
<li><a href="http://www.voltaicsystems.com/f5521-f3511" rel="nofollow">Voltaic V60 barrel adapter</a></li>
<li><a href="http://www.voltaicsystems.com/laptop-5525m-wire" rel="nofollow">Voltaic 5.5x2.5mm laptop cable</a></li>
</ul>
<p>The battery is connected to the Fuse 10W and the Arc 20W supplies extra power by connecting it to the “Solar Panel Output” on the Fuse 10W. To do this I needed to use one of the included adapters to bridge the V60 barrel adapter with the Arc 20W and then the 5.5x2.5mm wire to connect the V60 barrel adapter to the Fuse 10W. Check out <a href="http://www.voltaicsystems.com/blog/double-power-on-your-solar-charger/">this</a> guide for more information on how to do this.
The above setup works nice for dedicated trips to the beach or a long bike ride where I need a lot of power. But there are a few drawbacks</p>
<ul>
<li>You cannot leave your bike out with all that gear, it will get stolen! So it does take about 5 min. to mount / unmount the setup</li>
<li>The V60 lithium ion battery does not perform too well in the harsh and cold Danish winter. I might look into replacing it with a deep cycle lead acid battery that should perform better in all weather</li>
<li>The angles of the solar panels are less than optimal</li>
<li>The setup has to be adjusted when loading and offloading cargo</li>
</ul>
<p>The next project is to change the setup so both the front hub dynamo and the solar panels charge the same battery and mounting smaller solar panels permanently on the bike.</p>
<p><a href="https://odd-one-out.serek.eu/projects/bullitt-cargo-bike-voltaic-solar-panels/" rel="nofollow">Bullitt cargo bike with solar panels</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Bullitt cargo bike with solar panelsWindows 10 eGPU setup with Optimus!2016-01-31T00:00:00+00:002016-01-30T22:43:35+00:00https://odd-one-out.serek.eu/projects/windows-10-egpu-setup-optimus
<p><img src="/assets/images/windows-10-egpu-setup-optimus-feature.jpg" alt="" /></p>
<p>Last year I did a Thunderbolt 2 enabled external GPU setup using Windows 8.1. I did not upgrade right away when Windows 10 came out because Optimus was <a href="https://www.techinferno.com/index.php?/forums/topic/8918-egpu-window-10-optimus-mode-problem/">broken</a> which meant I could not use the internal laptop screen. Now NVIDIA has finally fixed the problem in the latest 361.75 driver as described in the release highlights:</p>
<blockquote>
<p>Beta support on GeForce GTX GPUs for external graphics over Thunderbolt 3</p>
</blockquote>
<p>I will be starting from scratch so this post assumes you already have</p>
<ul>
<li>A clean copy of Windows 10 installed and fully updated. You can try to upgrade from an older version of Windows, but this did not work for me.</li>
<li>Windows 10 is installed as EFI / UEFI. Check <a href="http://www.thewindowsclub.com/check-if-uefi-or-bios">this</a> post to see if you are running BIOS or UEFI/EFI</li>
<li>A similar hardware setup used in my post <a href="/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2/">here</a>. I use
<ul>
<li><a href="https://www.amazon.com/dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2 PCIe box</a></li>
<li><a href="http://www.moddiy.com/products/PCI%252dExpress-PCI%252dE-8X-to-16X-Riser-Card-Flexible-Ribbon-Extender-Cable-w%7B47%7DMolex-%252b-Solid-Capacitor.html">PCI-Express PCI-E 8X to 16X Riser Card Flexible Ribbon Extender Cable w/Molex</a></li>
<li><a href="https://www.amazon.com/dp/B00NVODXR4/" rel="nofollow" data-amazon-asin="[uk]B00NSXYEQW[us]B00NVODXR4[de][es][it][fr][ca]B00NSXYEQW">EVGA GeForce GTX 970 Superclocked ACX 2.0</a></li>
</ul>
</li>
<li>A MacBook without a discrete graphics card. I use a MacBook Pro late 2013</li>
</ul>
<h2 id="driver-installation">Driver installation</h2>
<ol>
<li>Turn the laptop and eGPU off</li>
<li>Plug in the thunderbolt cable from the eGPU setup to the laptop</li>
<li>Power on the eGPU setup</li>
<li>Power on the laptop and boot into Windows 10 (hold down the ALT key to get to the boot menu)</li>
<li>Confirm that the graphics card is detected in Device Manager</li>
</ol>
<figure>
<noscript><img src="/assets/images/windows-10-egpu-setup-optimus-Device-manager-basic-adapter.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/windows-10-egpu-setup-optimus-Device-manager-basic-adapter.jpg" alt="" class="lazyload fade-in" />
<figcaption>External graphics card detected in device manager before driver installation</figcaption>
</figure>
<ol start="6">
<li>Install NVIDIA driver (use 361.75 or later)</li>
<li>Reboot into Windows 10 (hold down ALT key for boot menu if needed)</li>
<li>The internal and external graphics card should now both be visible without any errors in Device Manager</li>
</ol>
<figure>
<noscript><img src="/assets/images/windows-10-egpu-setup-optimus-Device-manager-NVIDIA.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/windows-10-egpu-setup-optimus-Device-manager-NVIDIA.jpg" alt="" class="lazyload fade-in" />
<figcaption>External card now correctly detected with the NVIDIA driver installed</figcaption>
</figure>
<ol start="9">
<li>Confirm that the eGPU is working by doing a benchmark, I used <a href="http://www.geeks3d.com/gputest/">Geeks3D GpuTest</a></li>
</ol>
<figure>
<noscript><img src="/assets/images/windows-10-egpu-setup-optimus-Success.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/windows-10-egpu-setup-optimus-Success.jpg" alt="" class="lazyload fade-in" />
<figcaption>GPU benchmark under Windows 10 using the internal screen (Optimus)</figcaption>
</figure>
<h2 id="usage">Usage</h2>
<p>After the driver installation I do the following every time I need to use the setup:</p>
<ol>
<li>Make sure the laptop and eGPU setup is powered off and disconnected</li>
<li>Connect the laptop to the eGPU system using the Thunderbolt cable</li>
<li>Turn on the laptop and boot into the boot menu by holding down the ALT key</li>
<li>Turn on the eGPU system</li>
<li>Wait a few seconds (I can usually hear the graphics card fans starting) and then continue booting into Windows 10</li>
</ol>
<p>The above steps might be overkill, but for now I have successfully started the setup with no problems many times in a row.</p>
<h2 id="troubleshooting">Troubleshooting</h2>
<ul>
<li>If you boot into a blank screen you probably have the internal screen disabled. Do a full shutdown in Windows 10, disconnect the eGPU setup, boot into Windows 10 without the eGPU, shutdown again and follow the steps described in the section “Usage”. To shutdown with a blank screen you could try the following:
<ul>
<li>If you have access to an external monitor, connect this to the external graphics card and you should now see the login screen for Windows 10. Shutdown Windows 10 from here</li>
<li>If you don’t have access to an external monitor and want to do a proper shutdown, this trick worked for me. If it does not work try it again. When the blue light of the AKiTiO Thunder2 is off then you know the laptop is turned off.
<ul>
<li>Press ENTER</li>
<li>Type your Windows 10 password</li>
<li>Press ENTER</li>
<li>Wait a 10 seconds for Windows to start</li>
<li>Press CMD + R</li>
<li>Type “shutdown -s -t 0”</li>
<li>Press ENTER</li>
</ul>
</li>
</ul>
</li>
<li>If the blue light on the AKiTiO box does not light up when powering on the setup, check that the PCIe riser is firmly attached to the box and the GPU. Also make sure that the thunderbolt port is working (try using it with another device)</li>
<li>If you get an error 12 on the eGPU, try using a DSDT override as described in my previous post <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l">here</a></li>
</ul>
<h2 id="help-and-support">Help and support</h2>
<p>There is a large eGPU community out there. For the best help and support please visit these sites:</p>
<ul>
<li><a href="https://www.techinferno.com/index.php?/forums/forum/83-diy-e-gpu-projects/">TechInferno</a>: Perhaps the biggest source of info on DIY eGPU setups. This is the first place to look for answers</li>
<li><a href="https://egpu.io/diy-egpu-setup-1-30-nando4/">DIY eGPU setup</a>: Software created by Nando4 which make can make otherwise impossible eGPU combinations work!</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/windows-10-egpu-setup-optimus/" rel="nofollow">Windows 10 eGPU setup with Optimus!</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Windows 10 eGPU setup with Optimus!ESP8266 NodeMCU - Enabling modules in firmware2015-10-24T00:00:00+00:002015-10-24T21:31:21+00:00https://odd-one-out.serek.eu/projects/esp8266-nodemcu-dht22-custom-modules-firmware
<p><img src="/assets/images/esp8266-nodemcu-dht22-custom-modules-firmware-feature.png" alt="" /></p>
<p>I previously wrote a <a href="/projects/esp8266-nodemcu-dht22-mqtt-deep-sleep/">post</a> about using the ESP8266 NodeMCU firmware to measure temperature and humidity. I used a lua library to read the values from the DHT22 sensor, but then found out that many of the modules I need for my projects are already included in the NodeMCU firmware! Even better, at <a href="http://frightanic.com/nodemcu-custom-build/">frightanic.com</a> you can customise the NodeMCU firmware and the site will build the version for you and send a download link in a few minutes. Want the latest and greatest firmware? Choose the dev branch. Need more free memory? Choose only the modules you need.</p>
<h2 id="customise-nodemcu-firmware">Customise NodeMCU firmware</h2>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-dht22-custom-modules-firmware-configure.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-dht22-custom-modules-firmware-configure.png" alt="" class="lazyload fade-in" />
<figcaption>Choose which branch and which modules to enable and in a few minutes you will have a custom NodeMCU firmware emailed to you.</figcaption>
</figure>
<p>As you can see from the screenshot there are plenty of libraries for various components you might need. For this post I choose the “DHT” and “MQTT” module in addition to the default ones. Then click the download link in the mail to download the integer version. Follow my instructions in <a href="/projects/esp8266-development-kit-nodemcu-firmware-update-os-x/">this</a> post to flash the firmware and be sure to read the troubleshooting section if you run into problems. Connect to the ESP8266 and you should see something like this:</p>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="go">NodeMCU custom build by frightanic.com
branch: dev
commit: 093a895980fbd4ab8b3ebedcd6efe36e26419887
SSL: true
modules: node,file,gpio,wifi,net,tmr,adc,mqtt,dht
built on: 2015-10-13 18:26
powered by Lua 5.1.4
lua: cannot open init.lua
</span><span class="gp">></span></code></pre></figure>
<p>You are now running a custom-made NodeMCU firmware!</p>
<h2 id="test-setup-using-a-dht22-sensor">Test setup using a DHT22 sensor</h2>
<p>To test that we can actually use the built-in modules I wire up my ESP8266 with a DHT sensor as shown here:</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-DHT22.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-DHT22.png" alt="" class="lazyload fade-in" />
<figcaption>ESP8266 with a DHT22 sensor</figcaption>
</figure>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<p>The parts used are</p>
<ul>
<li><a href="https://www.aliexpress.com/item/V2-4M-4FLASH-NodeMcu-Lua-WIFI-Networking-development-board-Based-ESP8266/32448662166.html" rel="nofollow">ESP8266 NodeMCU development kit v1.0</a> (a.k.a V2) ~ 4.70 USD</li>
<li><a href="https://www.aliexpress.com/af/dht22.html?SearchText=dht22&blanktest=0&origin=n&jump=afs" rel="nofollow">DHT22 sensor</a> ~ 2.6 USD</li>
<li><a href="https://www.aliexpress.com/store/product/100pcs-1-4W-5-Carbon-Film-Resistor-10K-11K-12K-15K-18K-ohm/605870_32836975230.html" rel="nofollow">10K 5% resistor</a> ~ 1 USD (for 100 pieces)</li>
<li><a href="https://www.aliexpress.com/af/breadboard.html?SearchText=breadboard&blanktest=0&origin=n&jump=afs" rel="nofollow">Breadboard</a> ~ 1.5 USD</li>
<li><a href="https://www.aliexpress.com/af/Breadboard%25252dJumper%25252dCable%25252dWires%25252dKit.html?SearchText=Breadboard+Jumper+Cable+Wires+Kit&blanktest=0&origin=n&jump=afs" rel="nofollow">Cables</a> ~ 2.5 USD (for 100+ pieces)</li>
<li>Micro USB cable</li>
</ul>
<p>You can get these items from Amazon but the price is higher just take a look at the prices for a <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=nodemcu+development+board" rel="nofollow">ESP8266</a> development board.</p>
<h2 id="the-test-code">The test code</h2>
<p>Now we are ready to write some code! I have modified the code from my previous <a href="/projects/esp8266-nodemcu-dht22-mqtt-deep-sleep/">post</a> to use the built-in DHT library. It will wake up every 60 seconds, measure the temperature and humidity and send the data to a MQTT server. In addition I added a watchdog timer to deep sleep the device the logic does not complete within 4 seconds, e.g. if the wifi is down. Upload the code as <code class="highlighter-rouge">init.lua</code>.</p>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
</pre></td><td class="code"><pre><span class="c1">-- MQTT connect script with deep sleep</span>
<span class="c1">-- Remember to connect GPIO16 and RST to enable deep sleep</span>
<span class="c1">-- TODO: Log error codes to server</span>
<span class="c1">--############</span>
<span class="c1">--# Settings #</span>
<span class="c1">--############</span>
<span class="c1">--- MQTT ---</span>
<span class="n">mqtt_broker_ip</span> <span class="o">=</span> <span class="s2">"192.168.1.66"</span>
<span class="n">mqtt_broker_port</span> <span class="o">=</span> <span class="mi">1883</span>
<span class="n">mqtt_username</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">mqtt_password</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">mqtt_client_id</span> <span class="o">=</span> <span class="s2">""</span>
<span class="c1">--- WIFI ---</span>
<span class="n">wifi_SSID</span> <span class="o">=</span> <span class="s2">"wifi-ssid"</span>
<span class="n">wifi_password</span> <span class="o">=</span> <span class="s2">"wifi-password"</span>
<span class="c1">-- wifi.PHYMODE_B 802.11b, More range, Low Transfer rate, More current draw</span>
<span class="c1">-- wifi.PHYMODE_G 802.11g, Medium range, Medium transfer rate, Medium current draw</span>
<span class="c1">-- wifi.PHYMODE_N 802.11n, Least range, Fast transfer rate, Least current draw</span>
<span class="n">wifi_signal_mode</span> <span class="o">=</span> <span class="n">wifi</span><span class="p">.</span><span class="n">PHYMODE_N</span>
<span class="c1">-- If the settings below are filled out then the module connects</span>
<span class="c1">-- using a static ip address which is faster than DHCP and</span>
<span class="c1">-- better for battery life. Blank "" will use DHCP.</span>
<span class="c1">-- My own tests show around 1-2 seconds with static ip</span>
<span class="c1">-- and 4+ seconds for DHCP</span>
<span class="n">client_ip</span><span class="o">=</span><span class="s2">"192.168.1.100"</span>
<span class="n">client_netmask</span><span class="o">=</span><span class="s2">"255.255.255.0"</span>
<span class="n">client_gateway</span><span class="o">=</span><span class="s2">"192.168.1.1"</span>
<span class="c1">--- INTERVAL ---</span>
<span class="c1">-- In milliseconds. Remember that the sensor reading,</span>
<span class="c1">-- reboot and wifi reconnect takes a few seconds</span>
<span class="n">time_between_sensor_readings</span> <span class="o">=</span> <span class="mi">60000</span>
<span class="c1">--################</span>
<span class="c1">--# END settings #</span>
<span class="c1">--################</span>
<span class="c1">-- Setup MQTT client and events</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">mqtt</span><span class="p">.</span><span class="n">Client</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="mi">120</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
<span class="n">temperature</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">humidity</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1">-- Connect to the wifi network</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">wifi</span><span class="p">.</span><span class="n">STATION</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setphymode</span><span class="p">(</span><span class="n">wifi_signal_mode</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">config</span><span class="p">(</span><span class="n">wifi_SSID</span><span class="p">,</span> <span class="n">wifi_password</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">connect</span><span class="p">()</span>
<span class="k">if</span> <span class="n">client_ip</span> <span class="o">~=</span> <span class="s2">""</span> <span class="k">then</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">setip</span><span class="p">({</span><span class="n">ip</span><span class="o">=</span><span class="n">client_ip</span><span class="p">,</span><span class="n">netmask</span><span class="o">=</span><span class="n">client_netmask</span><span class="p">,</span><span class="n">gateway</span><span class="o">=</span><span class="n">client_gateway</span><span class="p">})</span>
<span class="k">end</span>
<span class="c1">-- DHT22 sensor logic</span>
<span class="k">function</span> <span class="nf">get_sensor_Data</span><span class="p">()</span>
<span class="n">dht</span><span class="o">=</span><span class="nb">require</span><span class="p">(</span><span class="s2">"dht"</span><span class="p">)</span>
<span class="n">status</span><span class="p">,</span><span class="n">temp</span><span class="p">,</span><span class="n">humi</span><span class="p">,</span><span class="n">temp_decimial</span><span class="p">,</span><span class="n">humi_decimial</span> <span class="o">=</span> <span class="n">dht</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="k">if</span><span class="p">(</span> <span class="n">status</span> <span class="o">==</span> <span class="n">dht</span><span class="p">.</span><span class="n">OK</span> <span class="p">)</span> <span class="k">then</span>
<span class="c1">-- Prevent "0.-2 deg C" or "-2.-6" </span>
<span class="n">temperature</span> <span class="o">=</span> <span class="n">temp</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="nb">math.abs</span><span class="p">(</span><span class="n">temp_decimial</span><span class="p">)</span><span class="o">/</span><span class="mi">100</span><span class="p">)</span>
<span class="n">humidity</span> <span class="o">=</span> <span class="n">humi</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="nb">math.abs</span><span class="p">(</span><span class="n">humi_decimial</span><span class="p">)</span><span class="o">/</span><span class="mi">100</span><span class="p">)</span>
<span class="c1">-- If temp is zero and temp_decimal is negative, then add "-" to the temperature string</span>
<span class="k">if</span><span class="p">(</span><span class="n">temp</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">temp_decimial</span><span class="o"><</span><span class="mi">0</span><span class="p">)</span> <span class="k">then</span>
<span class="n">temperature</span> <span class="o">=</span> <span class="s2">"-"</span><span class="o">..</span><span class="n">temperature</span>
<span class="k">end</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Temperature: "</span><span class="o">..</span><span class="n">temperature</span><span class="o">..</span><span class="s2">" deg C"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Humidity: "</span><span class="o">..</span><span class="n">humidity</span><span class="o">..</span><span class="s2">"%"</span><span class="p">)</span>
<span class="k">elseif</span><span class="p">(</span> <span class="n">status</span> <span class="o">==</span> <span class="n">dht</span><span class="p">.</span><span class="n">ERROR_CHECKSUM</span> <span class="p">)</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span> <span class="s2">"DHT Checksum error"</span> <span class="p">)</span>
<span class="n">temperature</span><span class="o">=-</span><span class="mi">1</span> <span class="c1">--TEST</span>
<span class="k">elseif</span><span class="p">(</span> <span class="n">status</span> <span class="o">==</span> <span class="n">dht</span><span class="p">.</span><span class="n">ERROR_TIMEOUT</span> <span class="p">)</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span> <span class="s2">"DHT Time out"</span> <span class="p">)</span>
<span class="n">temperature</span><span class="o">=-</span><span class="mi">2</span> <span class="c1">--TEST</span>
<span class="k">end</span>
<span class="c1">-- Release module</span>
<span class="n">dht</span><span class="o">=</span><span class="kc">nil</span>
<span class="nb">package.loaded</span><span class="p">[</span><span class="s2">"dht"</span><span class="p">]</span><span class="o">=</span><span class="kc">nil</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">loop</span><span class="p">()</span>
<span class="k">if</span> <span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">status</span><span class="p">()</span> <span class="o">==</span> <span class="mi">5</span> <span class="k">then</span>
<span class="c1">-- Stop the loop</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">stop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">m</span><span class="p">:</span><span class="n">connect</span><span class="p">(</span> <span class="n">mqtt_broker_ip</span> <span class="p">,</span> <span class="n">mqtt_broker_port</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Connected to MQTT"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" IP: "</span><span class="o">..</span> <span class="n">mqtt_broker_ip</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" Port: "</span><span class="o">..</span> <span class="n">mqtt_broker_port</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" Client ID: "</span><span class="o">..</span> <span class="n">mqtt_client_id</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" Username: "</span><span class="o">..</span> <span class="n">mqtt_username</span><span class="p">)</span>
<span class="c1">-- Get sensor data</span>
<span class="n">get_sensor_Data</span><span class="p">()</span>
<span class="n">m</span><span class="p">:</span><span class="n">publish</span><span class="p">(</span><span class="s2">"ESP8266/temperature"</span><span class="p">,</span><span class="n">temperature</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="n">m</span><span class="p">:</span><span class="n">publish</span><span class="p">(</span><span class="s2">"ESP8266/humidity"</span><span class="p">,</span><span class="n">humidity</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Going to deep sleep for "</span><span class="o">..</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">/</span><span class="mi">1000</span><span class="p">)</span><span class="o">..</span><span class="s2">" seconds"</span><span class="p">)</span>
<span class="n">node</span><span class="p">.</span><span class="n">dsleep</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span> <span class="p">)</span>
<span class="k">else</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Connecting..."</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="n">loop</span><span class="p">()</span> <span class="k">end</span><span class="p">)</span>
<span class="c1">-- Watchdog loop, will force deep sleep the operation somehow takes to long</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">4000</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="k">function</span><span class="p">()</span> <span class="n">node</span><span class="p">.</span><span class="n">dsleep</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span> <span class="k">end</span><span class="p">)</span></pre></td></tr></tbody></table></code></pre></figure>
<p>You should see a message like this every 60 seconds if you have set everything up correctly.</p>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="go">NodeMCU custom build by frightanic.com
branch: dev
commit: 093a895980fbd4ab8b3ebedcd6efe36e26419887
SSL: true
modules: node,file,gpio,wifi,net,tmr,adc,mqtt,dht
built on: 2015-10-13 18:26
powered by Lua 5.1.4
</span><span class="gp">></span> Connecting...
<span class="go">Connected to MQTT
IP: 192.168.1.66
Port: 1883
Client ID:
Username:
Temperature: 23.0 deg C
Humidity: 44.1%
Going to deep sleep for 60 seconds</span></code></pre></figure>
<p>The code is now using the built-in modules for the DHT22 library rather than a lua script library!</p>
<p><strong>UPDATE: 19-04-2016</strong><br />
A reader pointed out that the code could not handle negative temperatures with an integer build of NodeMCU, e.g. “-1.-5” instead of “-1.5”. This has now been corrected.</p>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-nodemcu-dht22-custom-modules-firmware/" rel="nofollow">ESP8266 NodeMCU - Enabling modules in firmware</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/ESP8266 NodeMCU - Enabling modules in firmwareESP8266 NodeMCU - DHT22 humidity sensor with MQTT and deep sleep2015-09-10T00:00:00+00:002015-09-10T21:39:25+00:00https://odd-one-out.serek.eu/projects/esp8266-nodemcu-dht22-mqtt-deep-sleep
<p><img src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-feature.png" alt="" /></p>
<p>After a lot of trial and error I have finally figured out how to connect a DHT22 sensor using a ESP8266, specifically the NodeMCU development 1.0 kit. After each sensor reading the ESP8266 will publish the data to a MQTT broker and then go into a deep sleep for 60 seconds to conserve power. I got strange readings depending on which DHT22 library I used, version of NodeMCU and NodeMCU firmware type (integer or float) so do not make the same mistakes I did! Read my getting started <a href="/projects/esp8266-nodemcu-getting-started-hello-world/">post</a> here for obtaining this board for less than 4 USD with free delivery.</p>
<h2 id="firmware-and-dependencies">Firmware and dependencies</h2>
<p>I flashed the ESP8266 with <a href="https://github.com/nodemcu/nodemcu-firmware/releases/download/0.9.6-dev_20150704/nodemcu_integer_0.9.6-dev_20150704.bin">nodemcu_integer_0.9.6-dev_20150704.bin</a>. Check out my post about reflashing firmware <a href="/projects/esp8266-development-kit-nodemcu-firmware-update-os-x/">here</a>. The DHT22 library I use can be found <a href="https://github.com/javieryanez/nodemcu-modules/blob/master/dht22/dht22_min.lua">here</a></p>
<h2 id="parts">Parts</h2>
<p>If you don’t mind waiting a few weeks I would recommend buying from AliExpress as I have done for the lowest price and free shipping, even to Europe!</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<table>
<thead>
<tr>
<th>Part</th>
<th>AliExpress</th>
<th>Amazon</th>
</tr>
</thead>
<tbody>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B010O1G1ES/" rel="nofollow" data-amazon-asin="[us]B010O1G1ES[ca]B019FBLEYU[uk]B010N1SPRK[de]B0182JOWOK[es][it][fr]">ESP8266 development board</a></td>
<td><a href="https://www.aliexpress.com/item/V2-4M-4FLASH-NodeMcu-Lua-WIFI-Networking-development-board-Based-ESP8266/32448662166.html" rel="nofollow">$4.2</a></td>
<td><a href="https://www.amazon.com/dp/B010O1G1ES/" rel="nofollow" data-amazon-asin="[us]B010O1G1ES[ca]B019FBLEYU[uk]B010N1SPRK[de]B0182JOWOK">$9</a></td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B00O8RIYYU/" rel="nofollow" data-amazon-asin="[us]B00O8RIYYU[ca]B00CIQLHZ6[uk][de]B00AZG1RBK[es][it][fr]">DHT22 humidity sensor</a></td>
<td><a href="https://www.aliexpress.com/item/1pcs-DHT22-digital-temperature-and-humidity-sensor-Temperature-and-humidity-module-AM2302-replace-SHT11-SHT15/32464173427.html" rel="nofollow">$2.7</a></td>
<td><a href="https://www.amazon.com/dp/B00O8RIYYU/" rel="nofollow" data-amazon-asin="[us]B00O8RIYYU[ca]B00CIQLHZ6[uk][de]B00AZG1RBK[es][it][fr]">$4.2</a></td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B0084A7PI8/" rel="nofollow" data-amazon-asin="[us][ca][es]B0084A7PI8[uk][de]B00JGFDKBQ[it][fr]B00PQC72ZS">breadboard</a></td>
<td><a href="https://www.aliexpress.com/item/1pcs-Quality-mini-bread-board-breadboard-8-5CM-x-5-5CM-400-holes-For-expansion-arduino/1906352269.html" rel="nofollow">$1.2</a></td>
<td><a href="https://www.amazon.com/dp/B0084A7PI8/" rel="nofollow" data-amazon-asin="[us][ca][es]B0084A7PI8[uk][de]B00JGFDKBQ[it][fr]B00PQC72ZS">$5.2</a></td>
</tr>
<tr>
<td>1x <a href="https://www.amazon.com/dp/B00B5RJF1M/" rel="nofollow" data-amazon-asin="[us]B00B5RJF1M[ca]B0087ZDSV8[uk]B004S0XA1O[de]B00IYUWT2A[es][it][fr]">10K resistor</a></td>
<td><a href="https://www.aliexpress.com/item/100pcs-10k-ohm-1-4W-10k-Metal-Film-Resistor-10kohm-0-25W-1-ROHS/32577051768.html" rel="nofollow">$0.7</a></td>
<td><a href="https://www.amazon.com/dp/B00B5RJF1M/" rel="nofollow" data-amazon-asin="[us]B00B5RJF1M[ca]B0087ZDSV8[uk]B004S0XA1O[de]B00IYUWT2A[es][it][fr]">$4.9</a></td>
</tr>
<tr>
<td><a href="https://www.amazon.com/dp/B014JOV4TI/" rel="nofollow" data-amazon-asin="[us]B014JOV4TI[ca]B0002H7AIQ[uk]B01B7M5S6K[de]B01B4HO30K[es]B01GQOJY7I[it]B01GZ2LP82[fr]B01IX7WMAM">Various breadboard wires</a></td>
<td><a href="https://www.aliexpress.com/af/breadboard%25252dwires.html?SearchText=breadboard+wires&blanktest=0&origin=n&jump=afs" rel="nofollow">$2.6</a></td>
<td><a href="https://www.amazon.com/dp/B014JOV4TI/" rel="nofollow" data-amazon-asin="[us]B014JOV4TI[ca]B0002H7AIQ[uk]B01B7M5S6K[de]B01B4HO30K[es]B01GQOJY7I[it]B01GZ2LP82[fr]B01IX7WMAM">$5.9</a></td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$11.4</td>
<td>$29.2</td>
</tr>
</tbody>
</table>
<h2 id="hardware-setup">Hardware setup</h2>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-DHT22.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-DHT22.png" alt="" class="lazyload fade-in" />
<figcaption>ESP8266 with deep sleep enabled and a DHT22 sensor</figcaption>
</figure>
<p>Using a ESP8266 NodeMCU 1.0 development kit and a bread board, we first enable deep sleep. Connecting the D0 and RST pin enables usage of the <code class="highlighter-rouge">node.dsleep()</code> command to put ESP8266 into deep sleep for a select period of time (yellow wire). Then we connect the 3.3V power to the DHT22 VCC pin which is the first pin (red wire). We make sure to ground the connection to the DHT22 (black wire) and lastly connect the DHT22 DATA pin to D4 (blue wire). According to the DHT22 documentation the 10K resistor between VCC and the DATA pin of the DHT22 is not needed, but some internet posts and kits do come with the resister, like the DHT22 kit from <a href="https://www.adafruit.com/products/385">Adafruit</a>. I choose to leave it in place, but saw no difference in operation when I left it out.</p>
<h2 id="code">Code</h2>
<h3 id="initlua">init.lua</h3>
<p>Autostart file. It will run the file <code class="highlighter-rouge">user.lua</code> if it exists and give us a 1 second delay to abort if needed</p>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre><span class="n">FileToExecute</span><span class="o">=</span><span class="s2">"user.lua"</span>
<span class="n">l</span> <span class="o">=</span> <span class="n">file</span><span class="p">.</span><span class="n">list</span><span class="p">()</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span><span class="n">v</span> <span class="k">in</span> <span class="nb">pairs</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="k">do</span>
<span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="n">FileToExecute</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"*** You've got 1 sec to stop timer ***"</span><span class="p">)</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Executing "</span><span class="o">..</span> <span class="n">FileToExecute</span><span class="p">)</span>
<span class="nb">dofile</span><span class="p">(</span><span class="n">FileToExecute</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span></pre></td></tr></tbody></table></code></pre></figure>
<h3 id="userlua">user.lua</h3>
<ol>
<li>Connects to the wifi defined in <code class="highlighter-rouge">wifi_SSID</code> with password <code class="highlighter-rouge">wifi_password</code>. You can tweak <code class="highlighter-rouge">wifi_signal_mode</code> for more range / less power consumption</li>
<li>When connected to the wifi it will connect to the MQTT broker, see the MQTT settings</li>
<li>Read the temperature and humidity using the DHT22 library</li>
<li>Publishes the temperature and humidity to the MQTT broker</li>
<li>Goes to deep sleep for 60 seconds which can be changed using the variable <code class="highlighter-rouge">time_between_sensor_readings</code></li>
</ol>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
</pre></td><td class="code"><pre><span class="c1">-- MQTT connect script with deep sleep</span>
<span class="c1">-- Remember to connect GPIO16 and RST to enable deep sleep</span>
<span class="c1">--############</span>
<span class="c1">--# Settings #</span>
<span class="c1">--############</span>
<span class="c1">--- MQTT ---</span>
<span class="n">mqtt_broker_ip</span> <span class="o">=</span> <span class="s2">"192.168.1.66"</span>
<span class="n">mqtt_broker_port</span> <span class="o">=</span> <span class="mi">1883</span>
<span class="n">mqtt_username</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">mqtt_password</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">mqtt_client_id</span> <span class="o">=</span> <span class="s2">""</span>
<span class="c1">--- WIFI ---</span>
<span class="n">wifi_SSID</span> <span class="o">=</span> <span class="s2">"wifi-Name"</span>
<span class="n">wifi_password</span> <span class="o">=</span> <span class="s2">"wifi-Password"</span>
<span class="c1">-- wifi.PHYMODE_B 802.11b, More range, Low Transfer rate, More current draw</span>
<span class="c1">-- wifi.PHYMODE_G 802.11g, Medium range, Medium transfer rate, Medium current draw</span>
<span class="c1">-- wifi.PHYMODE_N 802.11n, Least range, Fast transfer rate, Least current draw</span>
<span class="n">wifi_signal_mode</span> <span class="o">=</span> <span class="n">wifi</span><span class="p">.</span><span class="n">PHYMODE_N</span>
<span class="c1">-- If the settings below are filled out then the module connects</span>
<span class="c1">-- using a static ip address which is faster than DHCP and</span>
<span class="c1">-- better for battery life. Blank "" will use DHCP.</span>
<span class="c1">-- My own tests show around 1-2 seconds with static ip</span>
<span class="c1">-- and 4+ seconds for DHCP</span>
<span class="n">client_ip</span><span class="o">=</span><span class="s2">""</span>
<span class="n">client_netmask</span><span class="o">=</span><span class="s2">""</span>
<span class="n">client_gateway</span><span class="o">=</span><span class="s2">""</span>
<span class="c1">--- INTERVAL ---</span>
<span class="c1">-- In milliseconds. Remember that the sensor reading,</span>
<span class="c1">-- reboot and wifi reconnect takes a few seconds</span>
<span class="n">time_between_sensor_readings</span> <span class="o">=</span> <span class="mi">60000</span>
<span class="c1">--################</span>
<span class="c1">--# END settings #</span>
<span class="c1">--################</span>
<span class="c1">-- Setup MQTT client and events</span>
<span class="n">m</span> <span class="o">=</span> <span class="n">mqtt</span><span class="p">.</span><span class="n">Client</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="mi">120</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">)</span>
<span class="n">temperature</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">humidity</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1">-- Connect to the wifi network</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setmode</span><span class="p">(</span><span class="n">wifi</span><span class="p">.</span><span class="n">STATION</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">setphymode</span><span class="p">(</span><span class="n">wifi_signal_mode</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">config</span><span class="p">(</span><span class="n">wifi_SSID</span><span class="p">,</span> <span class="n">wifi_password</span><span class="p">)</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">connect</span><span class="p">()</span>
<span class="k">if</span> <span class="n">client_ip</span> <span class="o">~=</span> <span class="s2">""</span> <span class="k">then</span>
<span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">setip</span><span class="p">({</span><span class="n">ip</span><span class="o">=</span><span class="n">client_ip</span><span class="p">,</span><span class="n">netmask</span><span class="o">=</span><span class="n">client_netmask</span><span class="p">,</span><span class="n">gateway</span><span class="o">=</span><span class="n">client_gateway</span><span class="p">})</span>
<span class="k">end</span>
<span class="c1">-- DHT22 sensor logic</span>
<span class="k">function</span> <span class="nf">get_sensor_Data</span><span class="p">()</span>
<span class="n">DHT</span><span class="o">=</span> <span class="nb">require</span><span class="p">(</span><span class="s2">"dht22_min"</span><span class="p">)</span>
<span class="n">DHT</span><span class="p">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">temperature</span> <span class="o">=</span> <span class="n">DHT</span><span class="p">.</span><span class="n">getTemperature</span><span class="p">()</span>
<span class="n">humidity</span> <span class="o">=</span> <span class="n">DHT</span><span class="p">.</span><span class="n">getHumidity</span><span class="p">()</span>
<span class="k">if</span> <span class="n">humidity</span> <span class="o">==</span> <span class="kc">nil</span> <span class="k">then</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Error reading from DHT22"</span><span class="p">)</span>
<span class="k">else</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Temperature: "</span><span class="o">..</span><span class="p">(</span><span class="n">temperature</span> <span class="o">/</span> <span class="mi">10</span><span class="p">)</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="n">temperature</span> <span class="o">%</span> <span class="mi">10</span><span class="p">)</span><span class="o">..</span><span class="s2">" deg C"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Humidity: "</span><span class="o">..</span><span class="p">(</span><span class="n">humidity</span> <span class="o">/</span> <span class="mi">10</span><span class="p">)</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="n">humidity</span> <span class="o">%</span> <span class="mi">10</span><span class="p">)</span><span class="o">..</span><span class="s2">"%"</span><span class="p">)</span>
<span class="k">end</span>
<span class="n">DHT</span> <span class="o">=</span> <span class="kc">nil</span>
<span class="nb">package.loaded</span><span class="p">[</span><span class="s2">"dht22_min"</span><span class="p">]</span><span class="o">=</span><span class="kc">nil</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nf">loop</span><span class="p">()</span>
<span class="k">if</span> <span class="n">wifi</span><span class="p">.</span><span class="n">sta</span><span class="p">.</span><span class="n">status</span><span class="p">()</span> <span class="o">==</span> <span class="mi">5</span> <span class="k">then</span>
<span class="c1">-- Stop the loop</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">stop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">m</span><span class="p">:</span><span class="n">connect</span><span class="p">(</span> <span class="n">mqtt_broker_ip</span> <span class="p">,</span> <span class="n">mqtt_broker_port</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Connected to MQTT"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" IP: "</span><span class="o">..</span> <span class="n">mqtt_broker_ip</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" Port: "</span><span class="o">..</span> <span class="n">mqtt_broker_port</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" Client ID: "</span><span class="o">..</span> <span class="n">mqtt_client_id</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">" Username: "</span><span class="o">..</span> <span class="n">mqtt_username</span><span class="p">)</span>
<span class="c1">-- Get sensor data</span>
<span class="n">get_sensor_Data</span><span class="p">()</span>
<span class="n">m</span><span class="p">:</span><span class="n">publish</span><span class="p">(</span><span class="s2">"ESP8266/temperature"</span><span class="p">,(</span><span class="n">temperature</span> <span class="o">/</span> <span class="mi">10</span><span class="p">)</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="n">temperature</span> <span class="o">%</span> <span class="mi">10</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="n">m</span><span class="p">:</span><span class="n">publish</span><span class="p">(</span><span class="s2">"ESP8266/humidity"</span><span class="p">,(</span><span class="n">humidity</span> <span class="o">/</span> <span class="mi">10</span><span class="p">)</span><span class="o">..</span><span class="s2">"."</span><span class="o">..</span><span class="p">(</span><span class="n">humidity</span> <span class="o">%</span> <span class="mi">10</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">function</span><span class="p">(</span><span class="n">conn</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Going to deep sleep for "</span><span class="o">..</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">/</span><span class="mi">1000</span><span class="p">)</span><span class="o">..</span><span class="s2">" seconds"</span><span class="p">)</span>
<span class="n">node</span><span class="p">.</span><span class="n">dsleep</span><span class="p">(</span><span class="n">time_between_sensor_readings</span><span class="o">*</span><span class="mi">1000</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span><span class="p">)</span>
<span class="k">end</span> <span class="p">)</span>
<span class="k">else</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Connecting..."</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="n">loop</span><span class="p">()</span> <span class="k">end</span><span class="p">)</span></pre></td></tr></tbody></table></code></pre></figure>
<h3 id="dht22_minlua">dht22_min.lua</h3>
<p>Taken from <a href="https://github.com/javieryanez/nodemcu-modules/blob/master/dht22/dht22_min.lua">here</a></p>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
</pre></td><td class="code"><pre><span class="kd">local</span> <span class="n">e</span><span class="o">=...</span><span class="kd">local</span> <span class="n">a</span><span class="o">=</span><span class="p">{}</span><span class="nb">_G</span><span class="p">[</span><span class="n">e</span><span class="p">]</span><span class="o">=</span><span class="n">a</span>
<span class="kd">local</span> <span class="n">o</span>
<span class="kd">local</span> <span class="n">d</span>
<span class="k">function</span> <span class="nc">a</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="kd">local</span> <span class="n">r</span>
<span class="kd">local</span> <span class="n">t</span>
<span class="n">o</span><span class="o">=</span><span class="mi">0</span>
<span class="n">d</span><span class="o">=</span><span class="mi">0</span>
<span class="n">r</span><span class="o">=</span><span class="mi">0</span>
<span class="kd">local</span> <span class="n">i</span><span class="o">=</span><span class="n">gpio</span><span class="p">.</span><span class="n">read</span>
<span class="kd">local</span> <span class="n">l</span><span class="o">=</span><span class="p">{}</span><span class="k">for</span> <span class="n">e</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="mi">40</span><span class="p">,</span><span class="mi">1</span> <span class="k">do</span>
<span class="n">l</span><span class="p">[</span><span class="n">e</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span>
<span class="k">end</span>
<span class="kd">local</span> <span class="n">a</span><span class="o">=</span><span class="mi">0</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span><span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">gpio</span><span class="p">.</span><span class="n">HIGH</span><span class="p">)</span><span class="n">tmr</span><span class="p">.</span><span class="n">delay</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span><span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span><span class="p">)</span><span class="n">tmr</span><span class="p">.</span><span class="n">delay</span><span class="p">(</span><span class="mi">40</span><span class="p">)</span><span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">gpio</span><span class="p">.</span><span class="n">INPUT</span><span class="p">)</span><span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span><span class="k">do</span> <span class="k">end</span>
<span class="kd">local</span> <span class="n">n</span><span class="o">=</span><span class="mi">0</span>
<span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">==</span><span class="mi">1</span> <span class="ow">and</span> <span class="n">n</span><span class="o"><</span><span class="mi">500</span><span class="p">)</span><span class="k">do</span> <span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span> <span class="k">end</span>
<span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span><span class="k">do</span> <span class="k">end</span>
<span class="n">n</span><span class="o">=</span><span class="mi">0</span>
<span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">==</span><span class="mi">1</span> <span class="ow">and</span> <span class="n">n</span><span class="o"><</span><span class="mi">500</span><span class="p">)</span><span class="k">do</span> <span class="n">n</span><span class="o">=</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span> <span class="k">end</span>
<span class="k">for</span> <span class="n">d</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="mi">40</span><span class="p">,</span><span class="mi">1</span> <span class="k">do</span>
<span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">==</span><span class="mi">1</span> <span class="ow">and</span> <span class="n">a</span><span class="o"><</span><span class="mi">10</span><span class="p">)</span><span class="k">do</span>
<span class="n">a</span><span class="o">=</span><span class="n">a</span><span class="o">+</span><span class="mi">1</span>
<span class="k">end</span>
<span class="n">l</span><span class="p">[</span><span class="n">d</span><span class="p">]</span><span class="o">=</span><span class="n">a</span>
<span class="n">a</span><span class="o">=</span><span class="mi">0</span>
<span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span><span class="k">do</span> <span class="k">end</span>
<span class="k">end</span>
<span class="k">for</span> <span class="n">e</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">1</span> <span class="k">do</span>
<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">e</span><span class="p">]</span><span class="o">></span><span class="mi">4</span><span class="p">)</span><span class="k">then</span>
<span class="n">o</span><span class="o">=</span><span class="n">o</span><span class="o">+</span><span class="mi">2</span><span class="o">^</span><span class="p">(</span><span class="mi">16</span><span class="o">-</span><span class="n">e</span><span class="p">)</span><span class="k">end</span>
<span class="k">end</span>
<span class="k">for</span> <span class="n">e</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">1</span> <span class="k">do</span>
<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">e</span><span class="o">+</span><span class="mi">16</span><span class="p">]</span><span class="o">></span><span class="mi">4</span><span class="p">)</span><span class="k">then</span>
<span class="n">d</span><span class="o">=</span><span class="n">d</span><span class="o">+</span><span class="mi">2</span><span class="o">^</span><span class="p">(</span><span class="mi">16</span><span class="o">-</span><span class="n">e</span><span class="p">)</span><span class="k">end</span>
<span class="k">end</span>
<span class="k">for</span> <span class="n">e</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span><span class="mi">1</span> <span class="k">do</span>
<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">e</span><span class="o">+</span><span class="mi">32</span><span class="p">]</span><span class="o">></span><span class="mi">4</span><span class="p">)</span><span class="k">then</span>
<span class="n">r</span><span class="o">=</span><span class="n">r</span><span class="o">+</span><span class="mi">2</span><span class="o">^</span><span class="p">(</span><span class="mi">8</span><span class="o">-</span><span class="n">e</span><span class="p">)</span><span class="k">end</span>
<span class="k">end</span>
<span class="n">t</span><span class="o">=</span><span class="p">(</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="mi">255</span><span class="p">)</span><span class="o">+</span><span class="n">bit</span><span class="p">.</span><span class="n">rshift</span><span class="p">(</span><span class="n">o</span><span class="p">,</span><span class="mi">8</span><span class="p">)</span><span class="o">+</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">d</span><span class="p">,</span><span class="mi">255</span><span class="p">)</span><span class="o">+</span><span class="n">bit</span><span class="p">.</span><span class="n">rshift</span><span class="p">(</span><span class="n">d</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span><span class="n">t</span><span class="o">=</span><span class="n">bit</span><span class="p">.</span><span class="n">band</span><span class="p">(</span><span class="n">t</span><span class="p">,</span><span class="mi">255</span><span class="p">)</span><span class="k">if</span> <span class="n">d</span><span class="o">></span><span class="mi">32768</span> <span class="k">then</span>
<span class="n">d</span><span class="o">=-</span><span class="p">(</span><span class="n">d</span><span class="o">-</span><span class="mi">32768</span><span class="p">)</span><span class="k">end</span>
<span class="k">if</span><span class="p">(</span><span class="n">t</span><span class="o">-</span><span class="n">r</span><span class="o">>=</span><span class="mi">1</span><span class="p">)</span><span class="ow">or</span><span class="p">(</span><span class="n">r</span><span class="o">-</span><span class="n">t</span><span class="o">>=</span><span class="mi">1</span><span class="p">)</span><span class="k">then</span>
<span class="n">o</span><span class="o">=</span><span class="kc">nil</span>
<span class="k">end</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span><span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="n">gpio</span><span class="p">.</span><span class="n">HIGH</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nc">a</span><span class="p">.</span><span class="nf">getTemperature</span><span class="p">()</span><span class="k">return</span> <span class="n">d</span>
<span class="k">end</span>
<span class="k">function</span> <span class="nc">a</span><span class="p">.</span><span class="nf">getHumidity</span><span class="p">()</span><span class="k">return</span> <span class="n">o</span>
<span class="k">end</span>
<span class="k">return</span> <span class="n">a</span></pre></td></tr></tbody></table></code></pre></figure>
<h2 id="result">Result</h2>
<p>If everything went well you should see the following message every 60 seconds:</p>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="go">NodeMCU 0.9.6 build 20150704 powered by Lua 5.1.4
*** You've got 1 sec to stop timer ***
</span><span class="gp">></span> Executing user.lua
<span class="go">Connecting...
Connected to MQTT
IP: 192.168.1.66
Port: 1883
Client ID:
Username:
Temperature: 24.9 deg C
Humidity: 49.9%
Going to deep sleep for 60 seconds</span></code></pre></figure>
<p>You now have a tiny ESP8266 based sensor that pushes data from the DHT22 sensor to a MQTT server!</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-final-setup.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-dht22-mqtt-deep-sleep-final-setup.jpg" alt="" class="lazyload fade-in" />
<figcaption>ESP8266 NodeMCU 1.0 development kit and a DHT22 sensor with deep sleep enabled. Not pretty, but it works!</figcaption>
</figure>
<p><strong>UPDATE: 11-10-2015</strong><br />
<code class="highlighter-rouge">user.lua</code> updated to be more battery efficient. Default wifi mode is now using 802.11n and optionally you can add <code class="highlighter-rouge">client_ip</code>, <code class="highlighter-rouge">client_netmask</code> and <code class="highlighter-rouge">client_gateway</code> for bypassing DHCP and using a static ip when reconnecting to the wifi, saving a few seconds. Finally you can drop the <code class="highlighter-rouge">init.lua</code> to eliminate an additional second.</p>
<p><strong>UPDATE: 24-10-2015</strong><br />
I have since updated the script to use the built-in DHT22 module in the NodeMCU firmware itself. Check out my post <a href="/projects/esp8266-nodemcu-dht22-custom-modules-firmware/">here</a> to flash the ESP8266 with this module enabled and the modified code.</p>
<p><strong>UPDATE: 20-03-2016</strong><br />
A post using the built-in DHT22 module and integrating to ThingSpeak instead of MQTT can be seen <a href="/projects/esp8266-nodemcu-dht22-thingspeak/">here</a></p>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-nodemcu-dht22-mqtt-deep-sleep/" rel="nofollow">ESP8266 NodeMCU - DHT22 humidity sensor with MQTT and deep sleep</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/ESP8266 NodeMCU - DHT22 humidity sensor with MQTT and deep sleepUpdate ESP8266 development kit NodeMCU firmware using OS X2015-08-30T00:00:00+00:002015-08-30T20:04:13+00:00https://odd-one-out.serek.eu/projects/esp8266-development-kit-nodemcu-firmware-update-os-x
<p>I have <a href="/projects/esp8266-getting-started-hello-world/">previously</a> written a small guide to getting started programming the ESP8266 development kit with the NodeMCU firmware. This post assumes that you have a fully working setup. Specifically I use the <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=nodemcu+esp8266" rel="nofollow">Seeedstudio NodeMCU v2 - Lua based ESP8266 development kit</a>. I will flash to the latest version of <a href="http://nodemcu.com/index_en.html">NodeMCU</a>.</p>
<h2 id="update-the-firmware">Update the firmware</h2>
<ol>
<li>Connect the ESP8266 via a micro-usb cable to the computer</li>
<li>Make sure no program is using the serial port to the ESP8266</li>
<li>Download and unpack <a href="https://github.com/themadinventor/esptool">esptool</a>, either as a <a href="https://github.com/themadinventor/esptool/archive/master.zip">zip</a> file or using git clone:</li>
</ol>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="gp">$</span>git clone https://github.com/themadinventor/esptool.git</code></pre></figure>
<ol start="4">
<li>OS X (Yosemite) already comes with python 2.7, but we need to install the <code class="highlighter-rouge">pySerial</code> dependency. Open a terminal and type</li>
</ol>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="gp">$</span><span class="nb">sudo </span>python setup.py <span class="nb">install</span></code></pre></figure>
<ol start="5">
<li>Download the latest ESP8266 NodeMCU firmware from <a href="https://github.com/nodemcu/nodemcu-firmware/releases/latest">here</a>. Get the <code class="highlighter-rouge">nodemcu_integer_*.bin</code> file if you are unsure, for this example the newest version was <code class="highlighter-rouge">nodemcu_integer_0.9.6-dev_20150704.bin</code></li>
<li>Go to the esptool folder, e.g.</li>
</ol>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="gp">$</span><span class="nb">cd</span> ~/Downloads/esptool</code></pre></figure>
<ol start="7">
<li>Flash the firmware using the following command. Replace <code class="highlighter-rouge">/dev/tty.SLAB_USBtoUART</code> with the name of the serial port you are using and <code class="highlighter-rouge">~/Downloads/nodemcu_integer_0.9.6-dev_20150704.bin</code> with the path to the firmware you downloaded in step 5.</li>
</ol>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="gp">$</span><span class="nb">sudo </span>python esptool.py <span class="nt">--baud</span> 921600 <span class="nt">--port</span> /dev/tty.SLAB_USBtoUART write_flash <span class="nt">-fm</span> dio 0x00000 ~/Downloads/nodemcu_integer_0.9.6-dev_20150704.bin</code></pre></figure>
<ol start="8">
<li>If everything is done right you should see the following</li>
</ol>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="go">Connecting...
Erasing flash...
Writing at 0x00070c00... (100 %)
Leaving...</span></code></pre></figure>
<ol start="9">
<li>Reconnect to the ESP8266 using <a href="http://esp8266.ru/esplorer/">ESPlorer</a> or any other similar software and confirm that the ESP8266 is updated to the newest version. Using the RST button will restart the device and print the version at the boot</li>
</ol>
<h2 id="troubleshooting">Troubleshooting</h2>
<ul>
<li>If unable to connect to the board after successfully flashing it you might try to remove the <code class="highlighter-rouge">-fm dio</code> parameter in step 7 and re-run it. For this particular version of NodeMCU and board from Seeedstudio I needed to add the parameter as explained <a href="http://www.seeedstudio.com/depot/NodeMCU-v2-Lua-based-ESP8266-development-kit-p-2415.html">here</a> (search for DIO in the comments)</li>
<li>If using python3 you will run into many error messages about invalid print statements. Apparently the introduced stricter enforcement of how to create print statements in python3 and the esptool source code using an invalid version. Downgrade to python 2.7 seems to be the easy way out unless you want to fix the code (should be easy)</li>
<li>If you can not reconnect after flashing using baud 9600, but you see the boot loader at baud 74880, then sometimes you need to reflash the old AT firmware. Go to <a href="https://github.com/esp8266/esp8266-wiki/tree/master/sdk">https://github.com/esp8266/esp8266-wiki/tree/master/sdk</a> and download <a href="https://github.com/esp8266/esp8266-wiki/blob/master/sdk/esp_iot_sdk_v0.9.5_15_01_23.zip">esp_iot_sdk_v0.9.5_15_01_23.zip</a>. Unpack the zip file and follow the instruction in the <code class="highlighter-rouge">bin/at/readme.txt</code> file. Specifically I refreshed the device using the following 4 commands:</li>
</ul>
<figure class="highlight"><pre><code class="language-terminal" data-lang="terminal"><span class="gp">$</span><span class="nb">sudo </span>python esptool.py <span class="nt">--baud</span> 921600 <span class="nt">--port</span> /dev/tty.SLAB_USBtoUART write_flash <span class="nt">-fm</span> dio 0x00000 ~/Downloads/esp_iot_sdk_v0.9.5/bin/boot_v1.2.bin
<span class="gp">$</span><span class="nb">sudo </span>python esptool.py <span class="nt">--baud</span> 921600 <span class="nt">--port</span> /dev/tty.SLAB_USBtoUART write_flash <span class="nt">-fm</span> dio 0x01000 ~/Downloads/esp_iot_sdk_v0.9.5/bin/at/user1.512.new.bin
<span class="gp">$</span><span class="nb">sudo </span>python esptool.py <span class="nt">--baud</span> 921600 <span class="nt">--port</span> /dev/tty.SLAB_USBtoUART write_flash <span class="nt">-fm</span> dio 0x3e000 ~/Downloads/esp_iot_sdk_v0.9.5/bin/blank.bin
<span class="gp">$</span><span class="nb">sudo </span>python esptool.py <span class="nt">--baud</span> 921600 <span class="nt">--port</span> /dev/tty.SLAB_USBtoUART write_flash <span class="nt">-fm</span> dio 0x7e000 ~/Downloads/esp_iot_sdk_v0.9.5/bin/blank.bin</code></pre></figure>
<p>Then retry step 7 to 9 in the guide with the selected NodeMCU firmware.</p>
<ul>
<li>If unable to flash with the <code class="highlighter-rouge">Exception: Failed to connect</code> error message, then try to remove all components connected to the ESP8266. I get this error when trying to flash the module with the RST and D2 pin connected which is needed for deep sleep.</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-development-kit-nodemcu-firmware-update-os-x/" rel="nofollow">Update ESP8266 development kit NodeMCU firmware using OS X</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Flash the latest ESP8266 development kit NodeMCU firmware using OS X.ESP8266 NodeMCU - Getting started (Hello World)2015-08-29T00:00:00+00:002015-08-30T18:19:46+00:00https://odd-one-out.serek.eu/projects/esp8266-nodemcu-getting-started-hello-world
<p><img src="/assets/images/esp8266-nodemcu-getting-started-hello-world-feature.jpg" alt="" /></p>
<p>Thanks to a bit of donated funds I was finally ready to play around with the ESP8266 <sup id="fnref:ESP8266"><a href="#fn:ESP8266" class="footnote">1</a></sup>, a tiny and inexpensive wifi system on a chip (SoC), which you can use to read data from sensors, connect to the internet or even act as a webserver!</p>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-getting-started-hello-world-NodeMCU-dev-kit.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-getting-started-hello-world-NodeMCU-dev-kit.jpg" alt="" class="lazyload fade-in" />
<figcaption>A tiny Wifi SoC</figcaption>
</figure>
<p>This post describes how to get the parts and getting everything up and running using OS X. I will use an ESP8266 running open source firmware called <a href="http://nodemcu.com/index_en.html">NodeMCU</a>. This allows easy programming of the device using <a href="https://en.wikipedia.org/wiki/Lua_(programming_language)">Lua</a> scripts. Since the tools used in this post are cross-platform compatible, you should be able to use this guide even when running Windows or Linux.</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<h2 id="parts">Parts</h2>
<p>There are many ways to getting started, but using a development kit is the easiest in my opinion. I bought the <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=nodemcu+esp8266" rel="nofollow">Seeedstudio NodeMCU v2 - Lua based ESP8266 development kit</a>, but I quickly found out that you can get them at a bargain at <a href="https://www.aliexpress.com/item/V2-4M-4FLASH-NodeMcu-Lua-WIFI-Networking-development-board-Based-ESP8266/32448662166.html" rel="nofollow">AliExpress</a>. For around 3.5 USD you can get started and as long as you only buy one at a time the shipping is free (but very slow shipping)! I use these boards from AliExpress now. Make sure you get the NodeMCU development kit v1.0 (a.k.a V2).</p>
<h2 id="connecting-the-esp8266">Connecting the ESP8266</h2>
<ol>
<li>Install the CP2102 driver from <a href="https://www.silabs.com/products/mcu/Pages/USBtoUARTBridgeVCPDrivers.aspx">here</a>. If using a different ESP8266 development board you might need different drivers. If you are lucky like me, the instructions will be printed on the back of the board</li>
</ol>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-getting-started-hello-world-NodeMCU-dev-kit-back.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-getting-started-hello-world-NodeMCU-dev-kit-back.jpg" alt="" class="lazyload fade-in" />
<figcaption>Seeedstudio was nice enough to leave some instructions on the back</figcaption>
</figure>
<ol start="2">
<li>Plugin the USB cable to the ESP8266 and then to the computer</li>
<li>Open a terminal and type <code class="highlighter-rouge">ls -l /dev/tty.*</code>. If everything went well you should see an entry similar to <code class="highlighter-rouge">/dev/tty.SLAB_USBtoUART</code>. Make sure you are using a USB data cable. I was using a purely USB charging cable which prevented the device showing up. Switching to another cable worked</li>
<li>Download ESPlorer from <a href="http://esp8266.ru/esplorer-latest/?f=ESPlorer.zip">here</a></li>
<li>In Finder, click the ESPlorer.jar to run the program (requires Java). If you get the message: ““ESPlorer.jar” can’t be opened because it is from an unidentified developer” then go to <code class="highlighter-rouge">System Preferences --> Security & Privacy</code> and click “Open anyway”</li>
<li>Select the <code class="highlighter-rouge">/dev/cu.SLAB_USBtoUART</code> and set the bad rate to 9600. Then click the “Open” button</li>
</ol>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-getting-started-hello-world-ESPlorer_configuration.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-getting-started-hello-world-ESPlorer_configuration.jpg" alt="" class="lazyload fade-in" />
</figure>
<ol start="7">
<li>Push the RST button on the ESP8266, it is right next to the micro-usb port</li>
<li>You should now see a message similar to <code class="highlighter-rouge">NodeMCU 0.9.5 build 20150403 powered by Lua 5.1.4</code></li>
</ol>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-getting-started-hello-world-NodeMCU_connected.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-getting-started-hello-world-NodeMCU_connected.jpg" alt="" class="lazyload fade-in" />
</figure>
<p>Thats it! We are now ready for programming the device</p>
<h2 id="programming-the-esp8266">Programming the ESP8266</h2>
<p>The ESP8266 with the NodeMCU firmware executes Lua files. When booting the device it will look for a file called <code class="highlighter-rouge">init.lua</code> and execute this file. But first we will clear the device of every file</p>
<ol>
<li>In ESPlorer, click the format button to delete all files</li>
<li>Next copy / paste the following code into the left hand box in ESPlorer (taken from http://esp8266.co.uk/recipes/blink-demo/, but the site is currently offline)</li>
</ol>
<figure class="highlight"><pre><code class="language-lua" data-lang="lua"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
</pre></td><td class="code"><pre><span class="c1">-- Config</span>
<span class="kd">local</span> <span class="n">pin</span> <span class="o">=</span> <span class="mi">4</span> <span class="c1">--> GPIO2</span>
<span class="kd">local</span> <span class="n">value</span> <span class="o">=</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span>
<span class="kd">local</span> <span class="n">duration</span> <span class="o">=</span> <span class="mi">1000</span> <span class="c1">--> 1 second</span>
<span class="c1">-- Function toggles LED state</span>
<span class="k">function</span> <span class="nf">toggleLED</span> <span class="p">()</span>
<span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span> <span class="k">then</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">gpio</span><span class="p">.</span><span class="n">HIGH</span>
<span class="k">else</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">gpio</span><span class="p">.</span><span class="n">LOW</span>
<span class="k">end</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1">-- Initialise the pin</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">mode</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="n">gpio</span><span class="p">.</span><span class="n">OUTPUT</span><span class="p">)</span>
<span class="n">gpio</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="n">pin</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
<span class="c1">-- Create an interval</span>
<span class="n">tmr</span><span class="p">.</span><span class="n">alarm</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="n">duration</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">toggleLED</span><span class="p">)</span></pre></td></tr></tbody></table></code></pre></figure>
<ol start="3">
<li>Save the file as <code class="highlighter-rouge">init.lua</code>. This will automatically upload the file to the ESP8266</li>
</ol>
<figure>
<noscript><img src="/assets/images/esp8266-nodemcu-getting-started-hello-world-Save_to_ESP.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/esp8266-nodemcu-getting-started-hello-world-Save_to_ESP.jpg" alt="" class="lazyload fade-in" />
</figure>
<ol start="4">
<li>Now the blue onboard LED should blink on and off every second. If you restart the device, it will load the <code class="highlighter-rouge">init.lua</code> file and keep on blinking</li>
</ol>
<h2 id="conclusion">Conclusion</h2>
<p>I have yet to explore the possibility of this little nifty device, but it looks promising. Using the development kit is much easier, but more expensive. The ESP8266 chips alone are less than half the price of the development kit, but worth it for me. Check out my post on how to update to the newest NodeMCU <a href="/projects/esp8266-development-kit-nodemcu-firmware-update-os-x/">here</a>. Stay tuned for more posts!</p>
<div class="footnotes">
<ol>
<li id="fn:ESP8266">
<p>The <a href="https://en.wikipedia.org/wiki/ESP8266">ESP8266</a> is a low-cost Wi-Fi chip with full TCP/IP stack and MCU (microcontroller unit) capability <a href="#fnref:ESP8266" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
<p><a href="https://odd-one-out.serek.eu/projects/esp8266-nodemcu-getting-started-hello-world/" rel="nofollow">ESP8266 NodeMCU - Getting started (Hello World)</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Getting started with the tiny SoC wifi server ESP8266 using NodeMCU firmware on OSX.External graphics card (eGPU)2015-06-03T00:00:00+00:002015-06-03T17:38:56+00:00https://odd-one-out.serek.eu/projects/external-graphics-card-egpu
<p><img src="/assets/images/external-graphics-card-egpu-laptop-iGPU-eGPU-Optimus-feature.png" alt="" /></p>
<p>For the past year I have blogged about NVIDIA based external graphics card (eGPU) setups. This post will sum up my work, findings and recommendations. First I will briefly describe the concept, then the individual parts with my recommendation and lastly links to various guides on hardware and software setup, mostly my own posts.
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links --></p>
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<p>If you already know the basic concepts, then you can safely skip to the <a href="#parts">Parts</a> section or see my specific post on the subject <a href="#hardware-setup">here</a>. This post is meant as a basic introduction.</p>
<h2 id="why-an-external-graphics-card-at-all">Why an external graphics card at all?</h2>
<p>I like the idea of having a single modular computer. When I am on the road I have a small light laptop. When I get back home I plug the laptop into my eGPU setup and suddenly I have transformed the laptop into a desktop, with upgraded graphics, USB ports, hard disks and so on. I only have to maintain a single device, the laptop. And the beauty of it all is that you can upgrade the graphics card on devices that would otherwise not be easily upgradable, like</p>
<ul>
<li>MacBooks</li>
<li>iMacs</li>
<li>Mac Minis</li>
<li>Laptops with Thunderbolt 1 / 2, mini PCIe and Express cards slots</li>
</ul>
<div class="notice danger no_toc_section">
<p><strong>A warning to the reader:</strong> Not all combination of hardware and software will work, always use google to see if anybody else has similar hardware and gotten it to work. There is no shame in letting other people do the hard work for you! The safest thing is to buy parts you know other people have gotten to work, like I have in my blog posts.</p>
</div>
<p>You can also buy a finished eGPU enclosure like the <a href="https://www.amazon.com/dp/B00PCJXN0I/" rel="nofollow" data-amazon-asin="[us][ca]B00PCJXN0I[uk]B00VTV4UQ4[de][es][it][fr]B0183T2Y30">Dell Computer Alienware Graphics Amplifier</a>, but I have no experience with this and it only works on certain Alienware laptops.</p>
<h2 id="simplified-overview">Simplified overview</h2>
<p>Lets assume that a laptop is a device that communicates to various components through a PCIe bus. And lets assume that the laptop is Optimus<sup id="fnref:optimus"><a href="#fn:optimus" class="footnote">1</a></sup> enabled and has two graphics cards.</p>
<figure>
<noscript><img src="/assets/images/external-graphics-card-egpu-laptop-simplified.svg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-egpu-laptop-simplified.svg" alt="" class="lazyload fade-in" />
<figcaption>A simplified drawing of a laptop in regards to external connections and graphics cards</figcaption>
</figure>
<p>What is important to notice here is that we can have an integrated graphics card (iGPU) and / or a dedicated graphics card (dGPU). If both cards are present, then the iGPU will be used during normal usage and the dGPU when more graphic intensive tasks are executed. Notice that only the iGPU is connected to the LCD display, we will get back to this later and how it can be used in external graphics card setups.</p>
<p>Devices can be connected directly to the PCIe bus through external connections on the laptop. For external graphic card (eGPU) usages these are typically Thunderbolt, ExpressCard and Mini PCIe. An external graphics card setup merely takes advantage of this fact and attaches a graphics card outside the laptop through these connections.</p>
<figure>
<noscript><img src="/assets/images/external-graphics-card-egpu-eGPU-external-monitor.svg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-egpu-eGPU-external-monitor.svg" alt="" class="lazyload fade-in" />
<figcaption>External graphics card setup (eGPU) using an external monitor</figcaption>
</figure>
<p>In the above example the laptop now sees three graphics cards, where the eGPU is connected to an external monitor. The laptop communicates through the PCIe bus which is extended through a Thunderbolt connection and sends data to the eGPU which in turn displays data on the external monitor. This is an example of a eGPU setup using and external monitor.</p>
<p>What if we could eliminate the external monitor and use the internal LCD display? How is this even possible when the LCD display is only connected to the iGPU? NVIDIA and Intel solves this by using a technology known as Optimus. When a laptop is using its dedicated GPU (NVIDIA), it actually sends the data to display to the iGPU (Intel) which in turn sends to the LCD display. Therefore the iGPU is always responsible for displaying the output no matter which graphics card is used.</p>
<figure>
<noscript><img src="/assets/images/external-graphics-card-egpu-laptop-iGPU-dGPU-Optimus.svg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-egpu-laptop-iGPU-dGPU-Optimus.svg" alt="" class="lazyload fade-in" />
<figcaption>Using Optimus the dGPU sends data to be displayed to the iGPU</figcaption>
</figure>
<p>Attach another NVIDIA GPU externally to the PCIe bus and we can take advantage of this technology by letting the eGPU send data to the iGPU!</p>
<figure>
<noscript><img src="/assets/images/external-graphics-card-egpu-laptop-iGPU-eGPU-Optimus.svg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-egpu-laptop-iGPU-eGPU-Optimus.svg" alt="" class="lazyload fade-in" />
<figcaption>External graphics card setup (eGPU) using the internal LCD display</figcaption>
</figure>
<p>Now the eGPU is sending the data to be displayed through the Thunderbolt connection to the iGPU which in turn sends it to the LCD display. This is known as an internal / Optimus eGPU setup.</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-corning-cable.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-corning-cable.jpg" alt="" class="lazyload fade-in" />
<figcaption>The external graphics card does not even need to be close to the laptop!</figcaption>
</figure>
<p>Using an external monitor is the easiest to configure and setup. It has less requirements than using the internal laptop monitor. Accelerating the internal laptop screen using an eGPU setup requires integrated graphics from Intel that is Optimus<sup id="fnref:optimus:1"><a href="#fn:optimus" class="footnote">1</a></sup> compatible, NVIDIA graphics card and Windows. If running OS X then only the external monitor solution is supported.
There are workarounds and hacks on the internet if you don’t meet the above requirements to get the internal LCD working with an eGPU setup, but that is outside the scope of this post.</p>
<h2 id="parts">Parts</h2>
<p>To be able to plugin a graphics card externally you need</p>
<ol>
<li>A computer that has a Thunderbolt / ExpressCard / Mini PCIe port or slot</li>
<li>A PCIe enclosure that converts a Thunderbolt / ExpressCard / Mini PCIe connection into a standard PCIe slot<sup id="fnref:pci-express"><a href="#fn:pci-express" class="footnote">2</a></sup></li>
<li>A graphics card</li>
<li>A power supply</li>
<li>Computer case (optional)</li>
<li>External monitor (optional)</li>
</ol>
<p>If you are reading this post you most likely have everything already except a PCIe enclosure.</p>
<h3 id="computer">Computer</h3>
<p>First you need a device that can use an external graphics card. I would strongly recommend a device that has a Thunderbolt 2 port, but Thunderbolt 1, mini PCIe and Express card can also work at lower speeds / performance. It can be more difficult and / or impossible for an external eGPU setup to work you have a lot of memory in your laptop and / or a discrete GPU so be sure to check on google if that combination works.<br />
I use a 13 inch Retina MacBook Pro (late 2013 model) with 16 GB memory and would recommend the newest <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=Retina+MacBook+Pro" rel="nofollow">Retina MacBook Pro</a> without a discrete GPU (only Intel Iris Pro) or <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=MacBook+Air" rel="nofollow">MacBook Air</a>. I also have had very good experience with my old Lenovo T430s, but this has only a Thunderbolt 1 port. Be very sure you get the correct model, not all models have the Thunderbolt port.<br />
If you want to be able to use an NVIDIA graphics card to run an eGPU setup without an external monitor, then make sure the device supports Optimus. This requires an internal GPU (iGPU) from Intel.</p>
<h3 id="pcie-enclosure">PCIe enclosure</h3>
<p>The heart of it all, a PCIe enclosure enables us to connect regular PCIe cards like graphics cards through Thunderbolt, mini PCIe or Express card. I highly recommend the <a href="https://www.amazon.com//dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2 PCIe box</a> if you have a Thunderbolt port, it works and is very cheap compared to other PCIe enclosures I have used. You can spend twice to four times as much getting other enclosures, but it is not worth it in my opinion. I have previously used the <a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00FMJPWFW">Sonnet Echo Express SE II</a> with two PCIe ports, but I had a lot of trouble getting graphics card to work, most likely because of the two PCIe ports instead of one. The price is also 2-3 times higher than the AKiTiO Thunder2. If you don’t have a Thunderbolt port, then I recommend the <a href="https://www.amazon.com/dp/B00GWM5ZLO/" rel="nofollow" data-amazon-asin="[us]B00GWM5ZLO[ca][uk][de][es][it][fr]">Bplus PE4L-EC060A</a> if you have an Express card or the <a href="https://www.amazon.com/dp/B00S4M2UKO/" rel="nofollow" data-amazon-asin="[us]B00S4M2UKO[ca][uk][de][es][it][fr]">Bplus PE4L-PM060A</a> if you have a mini PCIe slot, it is only a third of the cost of a AKiTiO Thunderbolt solution! The bandwidth is only a quarter of the AKiTiO Thunder2, but it will still give you a nice boost in graphical power.</p>
<h3 id="graphics-card">Graphics card</h3>
<p>My recommendations here are based on experience, both my own and from the eGPU community. Any recent <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=nvidia+geforce" rel="nofollow">NVIDIA card</a> should work fine, both with an external monitor and the internal laptop screen through Optimus. <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=evga+nvidia+geforce" rel="nofollow">EVGA branded NVIDIA cards</a> are powered different internally and work better for eGPU setups. Before I used EVGA graphics cards I needed to hot plug and time when I powered on the different parts of my eGPU setup. I even needed to create my own PCIe riser cable with 12v power spliced into it from the ATX power supply, see more <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">here</a>. To be fair, once I switched to using Windows 8 UEFI, most of the above problems went away, but I would still recommend EVGA to iron out the last few quirks.</p>
<h3 id="power-supply">Power supply</h3>
<p>Any <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=modular+atx+psu" rel="nofollow">modular ATX power supply</a> with enough power to drive the graphics card(s) and enough PCIe power connectors for the chosen card(s). Optionally you might need a powered <a href="http://www.moddiy.com/products/PCI%252dExpress-PCI%252dE-8X-to-16X-Riser-Card-Flexible-Ribbon-Extender-Cable-w%7B47%7DMolex-%252b-Solid-Capacitor.html">PCIe riser</a> if the PCIe port cannot supply 75 watts of power and the graphics card cannot get enough power from the PCIe power connectors alone. If unsure, just get one!</p>
<p>An example from one of my comments on the subject:</p>
<blockquote>
<p>The power supply should be fine, it has a single PCIe connector which you need to power the GTX 960. However, since the GTX 960 only has a single 6pin PCIe connector (according to the tech specs <a href="http://us.msi.com/product/vga/GTX-960-2GD5T-OC.html#hero-specification">here</a>) and the AKiTiO Thunder2 is limited to 25 watt from the PCIe port, you only have 75 + 25 = 100 watts total to power your card. Most posts on the internet agree that you need at least 125 watts of power as described <a href="http://www.guru3d.com/articles-pages/msi-geforce-gtx-960-gaming-oc-review,7.html">here</a>.</p>
<p>Therefore you need to buy a powered molex PCIe riser to be able to supply up to 75 watts on the PCIe port on the AKiTiO Thunder2 which would bring the total up to a safe 150 watts. The ones I use and recommend can be bought <a href="http://www.moddiy.com/products/PCI%252dExpress-PCI%252dE-8X-to-16X-Riser-Card-Flexible-Ribbon-Extender-Cable-w%7B47%7DMolex-%252b-Solid-Capacitor.html">here</a>.</p>
<p>You can also find similar items on Amazon (search for “<a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=pcie+riser+powered+capacitor" rel="nofollow">pcie riser powered capacitor</a>”, but the quality might vary. If you don’t follow my recommendation then at least make sure that the riser:</p>
<ul>
<li>Is x8 or x16 to x16</li>
<li>Is powered (molex)</li>
<li>Has a capacitor</li>
<li>Has good reviews</li>
</ul>
</blockquote>
<h3 id="case-optional">Case (optional)</h3>
<p>The easiest way is to find a small PC case where you can fit the eGPU setup with enough ventilation. If you have chosen the <a href="https://www.amazon.com/dp/B00GWM5ZLO/" rel="nofollow" data-amazon-asin="[us]B00GWM5ZLO[ca][uk][de][es][it][fr]">Bplus PE4L-EC060A</a> or <a href="https://www.amazon.com/dp/B00S4M2UKO/" rel="nofollow" data-amazon-asin="[us]B00S4M2UKO[ca][uk][de][es][it][fr]">Bplus PE4L-PM060A</a> as a PCIe enclosure you can get the <a href="https://www.amazon.com/dp/B00L9UZVKO/" rel="nofollow" data-amazon-asin="[us]B00L9UZVKO[ca][uk][de][es][it][fr]">Bplus DIY box</a> as I have used before <a href="/projects/external-graphics-card-experiment-part-1/">here</a>. I have chosen to build my own exoskeleton cases using <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=OpenBeam" rel="nofollow">OpenBeam</a> and <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=MakerBeam" rel="nofollow">MakerBeam</a> construction kits as described <a href="/projects/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii/">here</a> and <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">here</a>.</p>
<h3 id="external-monitor-optional">External monitor (optional)</h3>
<p>Use the one you already have. If you want to purchase one specifically for the eGPU setup I recommend the following</p>
<ul>
<li>Should have more than one connection input. The reasoning behind this is that I like to have my eGPU always connected to my external monitor, but when I am just working I like to connect the laptop directly to the monitor. Hence at least two inputs.</li>
<li>If used for gaming purposes, the resolution of the monitor should be something the eGPU setup can handle.</li>
</ul>
<h2 id="hardware-setup">Hardware setup</h2>
<p>For <a href="https://www.amazon.com/dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2</a> based setups, please see my post <a href="/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2/">here</a>. A deprecated setup using <a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00FMJPWFW">Sonnet Echo Express SE II</a> can be seen <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">here</a>. If using the PE4L, please see my post <a href="/projects/external-graphics-card-experiment-part-1/">here</a>.</p>
<h2 id="software-setup">Software setup</h2>
<ul>
<li><a href="/projects/windows-10-egpu-setup-optimus/">Windows 10 Optimus setup</a>. Recommended setup.</li>
<li><a href="/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2/">AKiTiO Thunder2 using Windows 8 UEFI</a>. Recommended, UEFI just makes everything easier! Check <a href="http://www.thewindowsclub.com/check-if-uefi-or-bios">this</a> post to see if you are running BIOS or (U)EFI.</li>
<li><a href="/projects/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el/">PE4L using Windows 7 BIOS and DIY eGPU setup 1.30</a>. DIY eGPU setup is recommended when a workaround is needed to get the setup to work. Can disable the discrete GPU and rearrange devices in PCI space to free some much-needed memory and avoid the dreaded “error 12”</li>
<li><a href="/projects/egpu-osx-maverick-nvidia-gtx-760-using-pe4l/">PE4L using OS X 10.9 (Maverick)</a></li>
<li><a href="http://www.journaldulapin.com/2014/12/04/a-nvidia-maxwell-card-with-thunderbolt-on-a-mac-running-yosemite/">OS X10.10 (Yosemite) using NVIDIA Maxwell cards</a></li>
</ul>
<h2 id="help-and-support">Help and support</h2>
<p>There is a large eGPU community out there. For the best help and support please visit these sites:</p>
<ul>
<li><a href="https://egpu.io/">eGPU.io</a>: New site dedicated to eGPU, start looking for answers and help here</li>
<li><a href="https://forum.techinferno.com/index.php?/forums/forum/83-diy-e-gpu-projects/">TechInferno</a>: Perhaps the biggest source of info on DIY eGPU setups. This has been replaced by eGPU.io</li>
<li><a href="https://egpu.io/diy-egpu-setup-1-30-nando4/">DIY eGPU setup</a>: Software created by Nando4 which make can make otherwise impossible eGPU combinations work!</li>
<li><a href="http://www.journaldulapin.com/">Journaldulapin.com</a>: A few good posts on getting OS X (<a href="http://www.journaldulapin.com/2013/08/24/a-thunderbolt-gpu-on-a-mac-how-to/">Maverick</a>, <a href="http://www.journaldulapin.com/2014/12/04/a-nvidia-maxwell-card-with-thunderbolt-on-a-mac-running-yosemite/">Yosemite</a>) working with eGPU setups</li>
</ul>
<p>Please leave a comment if you feel I have missed something or just want to ask a question.</p>
<p><strong>UPDATE: 13-06-2015</strong><br />
Good news, it seems Thunderbolt 3 will officially support graphics cards, including hot plugging the card, read more <a href="http://www.anandtech.com/show/9331/intel-announces-thunderbolt-3">here</a>.</p>
<p><strong>UPDATE: 30-01-2016</strong><br />
Added link to Windows 10 Optimus setup</p>
<div class="footnotes">
<ol>
<li id="fn:optimus">
<p><a href="https://en.wikipedia.org/wiki/Nvidia_Optimus">Nvidia Optimus</a> is a computer GPU switching technology created by Nvidia which will seamlessly switch between two graphics adapters within a computer system in order to provide either maximum performance or minimum power draw from the system’s graphics rendering hardware. <a href="#fnref:optimus" class="reversefootnote">↩</a> <a href="#fnref:optimus:1" class="reversefootnote">↩<sup>2</sup></a></p>
</li>
<li id="fn:pci-express">
<p><a href="http://en.wikipedia.org/wiki/PCI_Express">PCI Express</a> (Peripheral Component Interconnect Express), also known as PCIe and PCI-e, is a high-speed serial computer expansion bus standard connecting. <a href="#fnref:pci-express" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
<p><a href="https://odd-one-out.serek.eu/projects/external-graphics-card-egpu/" rel="nofollow">External graphics card (eGPU)</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/External graphics card (eGPU) - the fundamentals explained.eGPU case built around AKiTiO Thunder 22015-03-16T00:00:00+00:002015-03-16T20:15:00+00:00https://odd-one-out.serek.eu/projects/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii
<p><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-feature.jpg" alt="" /></p>
<p>I decided to recreate a smaller version of the eGPU case I made in my <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">previous</a> setup. I combine an AKiTiO Thunder2 board and my old Sonnet Echo Express SE II to have a graphics card, SSD drive and a pair of USB 3.0 ports. There is room for an additional hard drive and PCI-e slot. The setup is cooled using two 200mm fans, one fan cooling the graphics cards, the other the laptop.</p>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-setup-laptop.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-setup-laptop.jpg" alt="" class="lazyload fade-in" />
<figcaption>My eGPU setup with a 13 inch Retina MacBook Pro attached</figcaption>
</figure>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<h2 id="parts">Parts</h2>
<p>Check out my previous posts on the <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">Sonnet Echo Express SE II</a> and <a href="/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2/">AKiTiO Thunder2</a>. The only difference in parts is that I ditched the Sonnet power supply by powering the whole setup using a molex to barrel cable using <a href="https://www.techinferno.com/index.php?/forums/topic/6543-guide-making-a-molex-to-barrel-adapter/">this</a> guide. You don’t need both boards, but since I have them both I integrated them both.</p>
<h2 id="build-process">Build process</h2>
<p>Building the case took two days of trial and error, but once I get the basic design below done the reset was just installing the boards from the Sonnet and AKiTiO and the top fan.</p>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-case_in_progress.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-case_in_progress.jpg" alt="" class="lazyload fade-in" />
<figcaption>PSU, GPU and the side fan installed</figcaption>
</figure>
<p>To reduce the overall size of the setup I removed the boards from the Sonnet and AKiTiO. I used <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=MakerBeam" rel="nofollow">MakerBeam</a> beams and screw standoffs to secure the boards to the case.</p>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-AKiTiO_PCB.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-AKiTiO_PCB.jpg" alt="" class="lazyload fade-in" />
<figcaption>Using MakerBeam beams to secure the AKiTiO board</figcaption>
</figure>
<h2 id="the-case">The case</h2>
<p>The final case can be seen below. The laptop is a MacBook Pro retina 13 inch. The setup cannot get much smaller without reducing the size of the fans</p>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-setup.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-setup.jpg" alt="" class="lazyload fade-in" />
<figcaption>eGPU case</figcaption>
</figure>
<h3 id="top">Top</h3>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-top.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-top.jpg" alt="" class="lazyload fade-in" />
<figcaption>The top is designed to cool the connected laptop</figcaption>
</figure>
<p>The top is designed to hold and cool a laptop using the large <a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B000V6FKGM">200mm fan</a>. Several self adhesive rubber pads are placed to protect the laptop from scratches. The thunderbolt cable is used to connect the laptop to the setup.</p>
<h3 id="side---gpu-fan">Side - GPU fan</h3>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side-fan.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side-fan.jpg" alt="" class="lazyload fade-in" />
<figcaption>Side – GPU fan</figcaption>
</figure>
<p>A 200mm fan is used to assist cooling the graphics card. Running the fan at low speed the graphics card will almost never use its own fans.</p>
<h3 id="side---akitio">Side - AKiTiO</h3>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side-akitio.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side-akitio.jpg" alt="" class="lazyload fade-in" />
<figcaption>Side – AKiTiO</figcaption>
</figure>
<ol>
<li>ATX power supply, mounted using <a href="https://www.amazon.com/dp/B0196FHQK6/" rel="nofollow" data-amazon-asin="[us]B0196FHQK6[ca][uk][de][es][it][fr]us">OpenBeam L brackets</a></li>
<li>Thunderbolt cable connecting the <a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00FMJPWFW">Sonnet Echo Express SE II</a> on the other side of the case</li>
<li>Thunderbolt cable for the laptop</li>
<li><a href="https://www.amazon.com/dp/B00NVODXR4/" rel="nofollow" data-amazon-asin="[us]B00NVODXR4[ca][uk][de][es][it][fr]B00NSXYEQW">EVGA GeForce GTX 970</a> graphics card</li>
<li><a href="https://www.amazon.com/dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2</a> board mounted on the side. Notice that since I am using a powered PCI-e riser I do not need to connect the power supply unit to the DC jack</li>
<li>Fan control for the two <a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B000V6FKGM">200mm fans</a></li>
</ol>
<h3 id="side---sonnet">Side - Sonnet</h3>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side_sonnet.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side_sonnet.jpg" alt="" class="lazyload fade-in" />
<figcaption>Side – Sonnet</figcaption>
</figure>
<ol>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B000V6FKGM">200mm fan</a> for cooling the graphics card</li>
<li><a href="https://www.amazon.com/dp/B00NVODXR4/" rel="nofollow" data-amazon-asin="[us]B00NVODXR4[ca][uk][de][es][it][fr]B00NSXYEQW">EVGA GeForce GTX 970</a> graphics card</li>
<li>DIY MOLEX to barrel converter</li>
<li><a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00FMJPWFW">Sonnet Echo Express SE II</a> with a SATA / USB combo card. The last PCI-e slot is not used</li>
</ol>
<h3 id="side---power-supply">Side - Power Supply</h3>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side_ATX.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-side_ATX.jpg" alt="" class="lazyload fade-in" />
<figcaption>Side – Power supply</figcaption>
</figure>
<p>Nothing much here except the ATX and the SSD disk. A smaller and modular power supply is on my to-do list.</p>
<h3 id="bottom">Bottom</h3>
<figure>
<noscript><img src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-bottom.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii-bottom.jpg" alt="" class="lazyload fade-in" />
<figcaption>Bottom</figcaption>
</figure>
<ol>
<li>SSD disk</li>
<li>ATX PSU</li>
<li><a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00FMJPWFW">Sonnet Echo Express SE II</a> board</li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B000V6FKGM">200mm fan</a> that cools the graphics card</li>
<li>Protective rubber feet</li>
<li><a href="https://www.amazon.com/dp/B00NVODXR4/" rel="nofollow" data-amazon-asin="[us]B00NVODXR4[ca][uk][de][es][it][fr]B00NSXYEQW">EVGA GeForce GTX 970</a> graphics card</li>
</ol>
<h2 id="whats-next">Whats next?</h2>
<ul>
<li>Installing a smaller modular PSU to reduce the number of cables</li>
<li>Installing a power strip in the case so the power adapter for the MacBook can be installed in the case itself</li>
<li>A small cable reel for a <a href="https://www.amazon.com/dp/B00HSTC496/" rel="nofollow" data-amazon-asin="[us][ca][uk][de][es][it][fr]B00HSTC496">10m optical thunderbolt cable</a> I have lying around to avoid cable clutter</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii/" rel="nofollow">eGPU case built around AKiTiO Thunder 2</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/eGPU case built around AKiTiO Thunder 2 and Sonnet Echo Express SE II. Custom open air case for optimal cooling of both graphics card and attached laptopThunderbolt 2 eGPU using AKiTiO Thunder22015-02-04T00:00:00+00:002015-02-04T19:38:00+00:00https://odd-one-out.serek.eu/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2
<p><img src="/assets/images/thunderbolt-2-egpu-setup-using-akitio-thunder2-feature.jpg" alt="" /></p>
<p>I wanted to try a simpler and cheaper external GPU (eGPU) setup than I have used <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">previously</a>. For this I use the AKiTiO Thunder2 which is a fairly inexpensive compared to the rest of the pack.
Setup, installation and use is much simpler than before (no voodoo, rain dance or luck needed anymore), to use the setup from is as simple as</p>
<ul>
<li>Plug in the thunderbolt cable from the eGPU setup</li>
<li>Turn on PSU</li>
<li>Turn on laptop and boot into Windows</li>
</ul>
<p>This is both using the internal monitor with Optimus enabled and using an external monitor.</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<p>The key differences from my previous setup is</p>
<ul>
<li><a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=evga+nvidia+geforce" rel="nofollow">EVGA branded NVIDIA cards</a> are powered different internally so I do not need to power on the PSU at specifics times</li>
<li>The thunderbolt PCIe box only have a single PCIe port. The multiplexing chip on boxes that have multiple PCIe ports is suspected of interfering with eGPU setups and therefore making it less plug and play</li>
</ul>
<h2 id="egpu-setup">eGPU Setup</h2>
<h3 id="parts">Parts</h3>
<ul>
<li><a href="https://www.amazon.com/dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2 PCIe box</a> - 216 USD</li>
<li><a href="http://www.moddiy.com/products/PCI%252dExpress-PCI%252dE-8X-to-16X-Riser-Card-Flexible-Ribbon-Extender-Cable-w%7B47%7DMolex-%252b-Solid-Capacitor.html">PCI-Express PCI-E 8X to 16X Riser Card Flexible Ribbon Extender Cable w/Molex</a> - 15 USD</li>
<li><a href="https://www.amazon.com/dp/B00NVODXR4/" rel="nofollow" data-amazon-asin="[us]B00NVODXR4[ca][de][uk][es][it][fr]B00NSXYEQW">EVGA GeForce GTX 970 Superclocked ACX 2.0</a> - 350 USD</li>
<li>ENERMAX PRO82+ PSU ~ 60 USD</li>
<li>Single paperclip</li>
</ul>
<p><strong>Total 641 USD</strong></p>
<p>For my readers who wants to build something similar I have a few recommendations:</p>
<ul>
<li>Get any <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=evga+nvidia+geforce" rel="nofollow">EVGA branded NVIDIA card</a>, these just work better for eGPU type setups</li>
<li>You don’t need an ATX power supply, but often they are the cheapest way of powering the setup. Get one that is <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=atx+psu+modular" rel="nofollow">modular</a> and has enough 6/8pin PEG connectors to power your chosen graphic card</li>
<li>Thunderbolt 2 is limited to PCIe x4 2.0, so it does not matter if you get a PCIe x4, x8 or x16 PCIe riser, but what does matter is getting a quality PCIe riser to prevent stability issues!</li>
</ul>
<h4 id="hardware">Hardware</h4>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-setup-using-akitio-thunder2-overview.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-setup-using-akitio-thunder2-overview.jpg" alt="" class="lazyload fade-in" />
<figcaption>eGPU setup</figcaption>
</figure>
<ol>
<li><a href="https://www.amazon.com/dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2 PCIe box</a></li>
<li><a href="https://www.amazon.com/dp/B00NVODXR4/" rel="nofollow" data-amazon-asin="[us]B00NVODXR4[ca][de][uk][es][it][fr]B00NSXYEQW">GTX 970 GPU</a></li>
<li>PSU</li>
<li>Powered PCIe riser</li>
</ol>
<p>Plug the GPU into the PCIe riser. The PICe riser is plugged into the AKiTiO box. Make sure it is firmly attached. Plug in power to the PCIe riser and GPU from the PSU and use the <a href="http://aphnetworks.com/tutorials/psu_paperclip_trick">paperclip trick</a> (c) to turn on the PSU. Plug in the PSU to the wall socket and thunderbolt cable from the AKiTiO box to your thunderbolt enabled computer. Notice that I have disconnected the fan in the AKiTiO box (a) and when using a powered PCIe riser there is no need to use the power supply unit that came with the AKiTiO box (b).</p>
<h4 id="software">Software</h4>
<ul>
<li>Windows 8.1 installed via bootcamp in UEFI mode.</li>
<li>Newest NVIDIA drivers</li>
<li>(Optional) Benchmarking software</li>
</ul>
<div class="notice warning no_toc_section">
<p><strong>UPDATE 30-01-2016:</strong> NVIDIA released a new driver for Windows 10 that finally fixes Optimus! Check out my post <a href="/projects/windows-10-egpu-setup-optimus/">here</a></p>
</div>
<h4 id="driver-installation">Driver installation</h4>
<ul>
<li>Turn off the laptop</li>
<li>Plug in the thunderbolt cable from the eGPU setup</li>
<li>Turn on PSU</li>
<li>Turn on laptop and boot into Windows</li>
<li>Install NVIDIA driver</li>
<li>Shutdown laptop</li>
<li>Boot into Windows. The internal and external GPU should now both be visible without any errors</li>
</ul>
<p>This will work both when using external monitors attached to the GPU or using Optimus to accelerate the internal screen of the laptop. Repeat step 1-4 to boot into Windows with the eGPU active.</p>
<h4 id="troubleshooting">Troubleshooting</h4>
<ul>
<li>When booting into Windows without an external monitor attached to the eGPU, sometimes the monitor of the laptop is blank.
<ul>
<li>Try the windows key + P followed by the left arrow and finally hit the enter key. Repeat this if you don’t see anything on the monitor up to 3 times.</li>
<li>Try attaching a monitor or shutdown Windows and try booting into Windows again.</li>
</ul>
</li>
<li>If the blue light on the AKiTiO box does not light up when powering on the setup, check that the PCIe riser is firmly attached to the box and the GPU. Also make sure that the thunderbolt port is working (try using it with another device)</li>
<li>If you get an error 12 on the eGPU, try using a DSDT override as described in my previous post <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">here</a></li>
</ul>
<h2 id="performance">Performance</h2>
<p>The reduced bandwidth from the setup does not impact frame rates in games as much as one would think, see <a href="http://www.techpowerup.com/reviews/NVIDIA/GTX_980_PCI-Express_Scaling/">here</a> for an excellent test using the new NVIDIA GTX 980.</p>
<p>The following tests are executed using a 13 inch retina MacBook Pro late 2013 with 16 GB ram. You can use any laptop with thunderbolt, but I recommend getting one with Thunderbolt 2 like the MacBook Pro. I have included my previous test result using my <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/">previous setup</a> with a GTX 760. The presets are described here:</p>
<h3 id="unigine-valley-10-benchmark">Unigine Valley 1.0 benchmark</h3>
<ul>
<li>Basic: 1280x720, DirectX 9, medium quality, 2x AA</li>
<li>Extreme: 1600x900, DirectX 11, ultra quality, 8x AA</li>
<li>Extreme HD: 1920x1080, DirectX 11, ultra quality, 8x AA</li>
</ul>
<h4 id="fps">FPS</h4>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Basic</th>
<th style="text-align: right">Extreme</th>
<th style="text-align: right">Extreme HD</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100</td>
<td style="text-align: right">14,7</td>
<td style="text-align: right">5,0</td>
<td style="text-align: right">3,8</td>
</tr>
<tr>
<td>GTX 760 (internal)</td>
<td style="text-align: right">40,0</td>
<td style="text-align: right">40,3</td>
<td style="text-align: right">32,4</td>
</tr>
<tr>
<td>GTX 760 (external)</td>
<td style="text-align: right">85,4</td>
<td style="text-align: right">44,7</td>
<td style="text-align: right">35,3</td>
</tr>
<tr>
<td>GTX 970 (internal)</td>
<td style="text-align: right">45,1</td>
<td style="text-align: right">53,5</td>
<td style="text-align: right">45,5</td>
</tr>
<tr>
<td>GTX 970 (external)</td>
<td style="text-align: right">69,4</td>
<td style="text-align: right">57,8</td>
<td style="text-align: right">N/A</td>
</tr>
</tbody>
</table>
<h4 id="score">Score</h4>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Basic</th>
<th style="text-align: right">Extreme</th>
<th style="text-align: right">Extreme HD</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100</td>
<td style="text-align: right">616</td>
<td style="text-align: right">208</td>
<td style="text-align: right">160</td>
</tr>
<tr>
<td>GTX 760 (internal)</td>
<td style="text-align: right">1674</td>
<td style="text-align: right">1686</td>
<td style="text-align: right">1354</td>
</tr>
<tr>
<td>GTX 760 (external)</td>
<td style="text-align: right">3575</td>
<td style="text-align: right">1870</td>
<td style="text-align: right">1479</td>
</tr>
<tr>
<td>GTX 970 (internal)</td>
<td style="text-align: right">1889</td>
<td style="text-align: right">2239</td>
<td style="text-align: right">1903</td>
</tr>
<tr>
<td>GTX 970 (external)</td>
<td style="text-align: right">2904</td>
<td style="text-align: right">2418</td>
<td style="text-align: right">N/A</td>
</tr>
</tbody>
</table>
<p>Using higher resolutions makes the difference between internal and external monitor using the GPU very small compared to lower resolutions or lower AA. Notice that my GTX 970 scores are lower than GTX 760 using an external monitor at low settings. I did retest using my GTX 970 card getting the same results. I do not currently own an external 1080p monitor, hence no result for Extreme HD.</p>
<h3 id="3dmark-benchmark">3DMark benchmark</h3>
<p>The presets are described here:</p>
<ul>
<li>Fire strike ultra (3840x2160)</li>
<li>Fire strike extreme (2560x1440)</li>
<li>Fire strike (1080p)</li>
<li>Sky diver</li>
<li>Cloud gate</li>
</ul>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Fire strike ultra</th>
<th style="text-align: right">Fire strike extreme</th>
<th style="text-align: right">Fire strike</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100</td>
<td style="text-align: right">N/A</td>
<td style="text-align: right">400</td>
<td style="text-align: right">921</td>
</tr>
<tr>
<td>GTX 760 (internal)</td>
<td style="text-align: right">N/A</td>
<td style="text-align: right">2492</td>
<td style="text-align: right">4209</td>
</tr>
<tr>
<td>GTX 970 (internal)</td>
<td style="text-align: right">2295</td>
<td style="text-align: right">3921</td>
<td style="text-align: right">5941</td>
</tr>
<tr>
<td>GTX 970 (external)</td>
<td style="text-align: right">2398</td>
<td style="text-align: right">4239</td>
<td style="text-align: right">6659</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Sky diver</th>
<th style="text-align: right">Cloud gate</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100</td>
<td style="text-align: right">4077</td>
<td style="text-align: right">5750</td>
</tr>
<tr>
<td>GTX 760 (internal)</td>
<td style="text-align: right">8660</td>
<td style="text-align: right">7975</td>
</tr>
<tr>
<td>GTX 970 (internal)</td>
<td style="text-align: right">12760</td>
<td style="text-align: right">9206</td>
</tr>
<tr>
<td>GTX 970 (external)</td>
<td style="text-align: right">14955</td>
<td style="text-align: right">11557</td>
</tr>
</tbody>
</table>
<p>A 4k monitor was not needed to run the high resolution test, but I need at least 3 GB video ram. Therefore no results for fire strike ultra on HD5100 and GTX 760.</p>
<h2 id="whats-next">Whats next?</h2>
<ul>
<li>Build a case for the setup using <a href="https://www.amazon.com/dp/B00G3J6GDM/" rel="nofollow" data-amazon-asin="[us][ca][de][uk][es][it][fr]B00G3J6GDM">OpenBeam</a> or <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=MakerBeam" rel="nofollow">MakerBeam</a><br />
<strong>UPDATE 01-04-2015:</strong> Done! See my post <a href="/projects/egpu-case-built-around-akitio-thunder-2-and-sonnet-echo-express-se-ii">here</a></li>
<li>Test if I can get this to work using OS X 10.10.2 as previously done <a href="/projects/egpu-osx-maverick-nvidia-gtx-70-using-pe4l">here</a></li>
<li>Move the Windows installation to my thunderbolt disk (<a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow">Sonnet Echo Express SE II</a> enclosure)</li>
<li>Test higher resolutions using external monitors</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2/" rel="nofollow">Thunderbolt 2 eGPU using AKiTiO Thunder2</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Thunderbolt 2 eGPU using AKiTiO Thunder2 PCIe box - graphics performance on a budget!DIY Ambilight without a pc2014-07-26T00:00:00+00:002014-07-26T22:24:00+00:00https://odd-one-out.serek.eu/projects/diy-ambilight-without-pc
<p><img src="/assets/images/diy-ambilight-without-pc-effect-feature.jpg" alt="" /></p>
<p>Ever wished you had Philips Ambilight for your tv or monitor? Well, make it yourself and save a buck or two! This post uses the ambi-tv system to create an Ambilight clone.</p>
<figure>
<noscript><img src="/assets/images/diy-ambilight-without-pc-effect.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-effect.jpg" alt="" class="lazyload fade-in" />
<figcaption>Example of my DIY Ambilight setup</figcaption>
</figure>
<p>Here is an example of the finished ambi-tv setup in action using a test demo.</p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/IKc895J9n-0?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<p>Here you can see the setup using a real video. The video is from <a href="http://www.sintel.org/">sintel.org</a>, although not the best showcase of ambi-tv, it is the least likely to get me in trouble over copyright. I can reveal that the setup looks wonderful using the official Philips Ambilight demo video found <a href="https://www.youtube.com/watch?v=jV8IFZ5Sa_k">here</a></p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/Z-F1kWZpApU?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<p>It simply needs a HDMI input to work, no other computers than the Raspberry Pi doing all the processing and controlling the LEDs behind the tv. The whole setup is around 310 USD to make since I live in Europe, if you live in the States or Asia it is cheaper to get the parts. See this excellent video from the maker of the ambi-tv system to get more information: <a href="https://www.youtube.com/watch?v=8cpQpGYtjR0">https://www.youtube.com/watch?v=8cpQpGYtjR0</a></p>
<h2 id="hardware-list">Hardware list</h2>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<ul>
<li><a href="https://www.amazon.com/dp/B009SQQF9C/" rel="nofollow" data-amazon-asin="[us]B009SQQF9C[de]B00LPESRUK[uk]B00KKUS3RM[ca]B00AKQA0X6">Raspberry Pi revision B</a> (60 USD)
<ul>
<li><strong>UPDATE 01-04-2015:</strong> I strongly recommend to get the new <a href="https://www.amazon.com/dp/B01CD5VC92/" rel="nofollow" data-amazon-asin="[us][de][uk][es][it][fr][ca]B01CD5VC92">Raspberry Pi 3 Model B</a> which has 6 times more processing power and twice the ram than the model I have used for the same price!</li>
</ul>
</li>
<li><a href="https://www.amazon.com/dp/B002V2WYK4/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B002V2WYK4">König 2 way HDMI splitter</a> (60 USD)</li>
<li>3 meters of <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=LPD8806+LED+strip" rel="nofollow">LPD8806 LED strip</a> (generic brand from China) (55 USD)</li>
<li>EasyCAP DC60 - USB 2.0 (fake copy from China, need one using the Fushicai chipset) (15 USD)</li>
<li><a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=HDMI+to+AV+composite+converter" rel="nofollow">HDMI to AV composite converter</a> (17 USD)</li>
<li><a href="http://www.adafruit.com/product/658" rel="nofollow">5V 10A powersupply</a> (30 USD)</li>
<li><a href="https://www.amazon.com/dp/B00G3J6GDM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00G3J6GDM">OpenBeam beams, brackets and nuts & bolts</a> (optional) (40 USD)</li>
<li><a href="https://www.av-cables.dk/elspareskinne/">Outlet power strip which automatically power devices on / off with the tv</a> (optional) (30 USD)</li>
<li>Miscellaneous cables (5 USD)</li>
</ul>
<h2 id="hardware-and-software-setup">Hardware and software setup</h2>
<p>I will not go into details, but follow this guide here: <a href="https://github.com/gkaindl/ambi-tv">https://github.com/gkaindl/ambi-tv</a>. Some additional information</p>
<h3 id="hardware">Hardware</h3>
<ol>
<li>Make sure the LED strip and Raspberry PI share the same powersupply / grounds. I got very erratic results before I did this</li>
</ol>
<h3 id="software">Software</h3>
<ol>
<li>Download the 2013-07-26-wheezy-raspbian image and use this to build your image. I had problems building the USB driver for the tv-grabber using newer images. Don’t even do a dist-upgrade, but you should be able to do this after getting the USB driver to work (untested, I did not do the dist upgrade)</li>
<li>Green and blue colors were switched so I followed these instruction to fix it: <a href="https://github.com/gkaindl/ambi-tv/issues/14">https://github.com/gkaindl/ambi-tv/issues/14</a></li>
<li>I cropped the borders until the flickering of lights stopped (slowly increase Crop-* in the v4l2-grab-source section of ambi.conf).</li>
<li>I increased blended-frames which introduces slight lag in the Ambilight, this is on purpose as this gives me a smoother effect during movies</li>
<li>The image auto logins and starts ambi-tv. Press CTRL+C to quit and edit the settings</li>
</ol>
<p>You can download my <a href="https://www.dropbox.com/s/4947g5meatfvbm2/ambi-tv.gz?dl=1">image</a> if you want to skip step 1-5. Login and password pi / pi. Just remember to edit the ambi-tv.conf file to suit your needs. To write the image to an SD-card, use <a href="http://sourceforge.net/projects/win32diskimager/">Win32 Disk Imager</a>. You need to use a SD card of at least 4GB. If you use a SD card greater than 4GB you can resize the image using <a href="http://softwarebakery.com/shrinking-images-on-linux">this</a> guide if you want to increase the size of the root partition.
This finished setup can be seen here, I still need to hide all the mess behind the tv</p>
<figure>
<noscript><img src="/assets/images/diy-ambilight-without-pc-setup-leds.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-setup-leds.jpg" alt="" class="lazyload fade-in" />
<figcaption>LEDs using OpenBeam construction kit. All LEDs are angled at 45 degrees outwards</figcaption>
</figure>
<figure>
<noscript><img src="/assets/images/diy-ambilight-without-pc-setup-back.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-setup-back.jpg" alt="" class="lazyload fade-in" />
<figcaption>The OpenBeams are attached to the tv using an old wall mount. The LED strips are attached using strips</figcaption>
</figure>
<figure>
<noscript><img src="/assets/images/diy-ambilight-without-pc-setup-the-rest.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-setup-the-rest.jpg" alt="" class="lazyload fade-in" />
<figcaption>Lots of messy cables and boxes, I plan to hide this behind the tv at some point. Not everything belongs to the ambi-tv setup</figcaption>
</figure>
<h2 id="accuracy">Accuracy</h2>
<p>Color accuracy is not perfect, but works well enough that I have no need to tweak it further. I expect tweaking the gamma setting in ambi.conf can get me better results.</p>
<figure class="gallery-2-col">
<a href="/assets/images/diy-ambilight-without-pc-red-image.jpg"><noscript><img src="/assets/images/diy-ambilight-without-pc-red-image.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-red-image.jpg" alt="Red image" class="lazyload fade-in" /></a>
<a href="/assets/images/diy-ambilight-without-pc-green-image.jpg"><noscript><img src="/assets/images/diy-ambilight-without-pc-green-image.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-green-image.jpg" alt="Green image" class="lazyload fade-in" /></a>
<figcaption>Red and green image. The green color is slightly off</figcaption>
</figure>
<figure class="gallery-2-col">
<a href="/assets/images/diy-ambilight-without-pc-blue-image.jpg"><noscript><img src="/assets/images/diy-ambilight-without-pc-blue-image.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-blue-image.jpg" alt="Blue image" class="lazyload fade-in" /></a>
<a href="/assets/images/diy-ambilight-without-pc-black-image.jpg"><noscript><img src="/assets/images/diy-ambilight-without-pc-black-image.jpg" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-black-image.jpg" alt="Black image" class="lazyload fade-in" /></a>
<figcaption>Blue and black image (lights are all off). The red light in the lower left corner is from the HDMI switch</figcaption>
</figure>
<p>The accuracy regarding what to show is good enough not to need any tweaking, but the ambi-tv.conf can be tweaked to increase accuracy.</p>
<figure>
<noscript><img src="/assets/images/diy-ambilight-without-pc-accuracy.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/diy-ambilight-without-pc-accuracy.jpg" alt="" class="lazyload fade-in" />
<figcaption>Accuracy of displayed color according to the screen. Can be perfected using the ‘led-inset-top’ option in ambi.conf</figcaption>
</figure>
<h2 id="lag">Lag</h2>
<p>Using <a href="https://www.youtube.com/watch?v=sr_vL2anfXA">this</a> youtube video as shown in the beginning of the post I tested the lag on the ambi-tv. If the “blended-frame” variable in ambi.conf is set quite low there is no lag on a Raspberry Pi as you can see again on this video.</p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/IKc895J9n-0?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<p>As stated before, I use a rather high “blended-frames” to introduce higher lag to have a more smooth transition during movies.</p>
<h2 id="limitations">Limitations</h2>
<ul>
<li>The ambi-tv setup turns on when the tv turns on because of the attached standby power controller, but startup delay is around 1 minute, which is the time my standby power controller turns on the Raspberry Pi and boots into the operating system. Minor issue</li>
<li>Up to several minutes when turning off the tv before the ambilight turns off. This is limited by my standby power controller or the tv not entering a low power state right away. One could implement some code that detects when all LEDs are blue (no signal) for more than 10 seconds and turn the LEDs off.</li>
<li>No remote control support for changing ambi-tv settings. This should be fairly easy using lirc and some IR receiver</li>
<li>Some flickering of LED light depending on settings</li>
</ul>
<h2 id="what-next">What next?</h2>
<ul>
<li>Calibrate color accuracy for better results, starting with gamma correction</li>
<li>IR setup to remotely change ambilight setting. At the moment it default to edge settings when turing on the tv</li>
<li>With Philips ambilight tv’s it is possible to connect <a href="https://www.amazon.com/dp/B00BSN8DN4/" rel="nofollow" data-amazon-asin="[us]B00BSN8DN4[de][uk]B00ID6US3M[es][it][fr]B016151IRQ[ca]B01BGJN81G">Philips Hue</a> light-bulbs and extend the ambilight effect beyond the immediate area around the tv. I should be able to do something similar with this DIY ambilight setup</li>
<li>Cleanup the mess behind the tv</li>
<li>I would like to replace the software with something written in C# since that is what I prefer to tinker with</li>
<li>For a “mere” 2000 USD I can get the new Philips 60 inch ambilight tv, <a href="http://www.slashgear.com/philips-elevation-ambilighthue-tv-eyes-on-06296712/">Elevation</a>, and for 200 USD more a <a href="https://www.amazon.com/dp/B00BSN8DN4/" rel="nofollow" data-amazon-asin="[us]B00BSN8DN4[de][uk]B00ID6US3M[es][it][fr]B016151IRQ[ca]B01BGJN81G">Philips Hue</a> lightbulb set. A bit more than the 300 USD total the ambi-tv costs, but when I do feel the urge to upgrade the size of the tv, it might as well be a Philips tv with ambilight</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/diy-ambilight-without-pc/" rel="nofollow">DIY Ambilight without a pc</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Inexpensive and immersive DIY Ambilight that does not have to be attached to a PC.eGPU using Sonnet Echo Express SE II2014-05-19T00:00:00+00:002014-05-19T23:42:00+00:00https://odd-one-out.serek.eu/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l
<p><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-feature.jpg" alt="" /></p>
<p>I recently upgraded to a new eGPU setup which is faster than the one I describe in this <a href="/projects/external-graphics-card-experiment-part-1">post</a>. It is built around the Sonnet Echo Express SE II and using a long thunderbolt cable and a thunderbolt dock with HDMI enables me to have a silent gaming setup built around my laptop. Adding a hard disk frees up some much-needed space on my laptop without sacrificing hard disk speed.</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<h2 id="features">Features</h2>
<ul>
<li>Thunderbolt 2 bandwidth, 20 Gbps to a single device (2 PCI-E 2.0 x4 slots)</li>
<li>PCI-E 2.0 x1 slot from my old <a href="/projects/external-graphics-card-experiment-part-1">setup</a> (daisy chained from Sonnet thunderbolt port)</li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">2x 200mm fans</a>, one for cooling the GPU, the other for cooling the laptop</li>
<li>2x SATA III ports, one used with 300GB solid state drive</li>
<li>2x USB 3.0 ports</li>
<li>A large ATX PSU that powers the GPU (1200 watt, more than enough for a dual GPU setup)</li>
<li>Smaller PSU that powers the sonnet and PICO psu</li>
<li>Open case built using an <a href="https://www.amazon.com/dp/B00G3J6GDM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00G3J6GDM">OpenBeam</a> construction kit</li>
<li><a href="https://www.amazon.com/dp/B00NIQPA30/" rel="nofollow" data-amazon-asin="[us]B00NIQPA30">CallDigit thunderbolt dock</a> (USB 3.0 ports, HDMI out, ethernet, audio out etc.)</li>
<li><a href="https://www.amazon.com/dp/B00HSTC496/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00HSTC496">33 feet Corning optical thunderbolt cable</a> + thunderbolt dock to enable quite gaming</li>
</ul>
<h2 id="setup">Setup</h2>
<h3 id="parts">Parts</h3>
<ul>
<li><a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00FMJPWFW">Sonnet Echo Express SE II</a> thunderbolt enclosure</li>
<li><a href="http://www.delock.de/produkte/G_89359/merkmale.html?setLanguage=en">Delock PCI Express card, 2x external USB 3.0 and 2x internal SATA III</a></li>
<li><a href="https://www.amazon.com/dp/B00G3J6GDM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00G3J6GDM">OpenBeam Precut Kit Black Anodised</a></li>
<li>Additional OpenBeams parts</li>
<li><a href="https://www.amazon.com/dp/B008Q7HUR0/" rel="nofollow" data-amazon-asin="[us]B008Q7HUR0[de][uk][es][it][fr][ca]B008O0ZKMQ">Corsair AX1200 PSU</a></li>
<li><a href="https://www.amazon.com/dp/B00HSTC496/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00HSTC496">33 feet Corning optical thunderbolt cable</a></li>
<li><a href="https://www.amazon.com/dp/B00NIQPA30/" rel="nofollow" data-amazon-asin="[us]B00NIQPA30">CallDigit thunderbolt dock</a></li>
<li>PCI-E riser (x4 to x8), modified to enable pci delay</li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca] B000V6FKGM">2x 200mm Antec Bigboy fans</a></li>
<li>0,5m thunderbolt cable</li>
<li><a href="https://www.amazon.com/dp/B00H707RP2/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00H707RP2">Gigabyte GeForce GTX 760 2GB (GV-N760OC-2GD (REV. 2.0))</a></li>
<li>2,5mm DC barrel plugs and cables</li>
<li>300GB Solid State Drive</li>
<li><a href="https://www.amazon.com/dp/B005TWE5E6/" rel="nofollow" data-amazon-asin="[us]B005TWE5E6[de]B0071IHQBK">picoPSU-80 12V</a></li>
<li><a href="http://www.hwtools.net/Adapter/PE4L%20V2.1.html">PE4L</a> (Parts from my old eGPU <a href="/projects/external-graphics-card-experiment-part-1">setup</a>)</li>
<li><a href="https://www.amazon.com/dp/B0080MQJJ6/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B0080MQJJ6">Sonnet Echo Express Adapter Pro</a> (Parts from my old eGPU <a href="/projects/external-graphics-card-experiment-part-1">setup</a>)</li>
<li><a href="http://www.velleman.eu/products/view/?id=408364">Velleman remote control switch set</a></li>
</ul>
<h3 id="the-case">The case</h3>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-right-back.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-right-back.jpg" alt="" class="lazyload fade-in" />
<figcaption>Right / back side</figcaption>
</figure>
<ol>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm GPU fan</a></li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm laptop fan</a></li>
<li><a href="https://www.amazon.com/dp/B00H707RP2/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00H707RP2">GPU</a></li>
<li>Room for a secondary GPU (SLI or PhysX dedicated card)</li>
<li>2x USB 3.0 ports</li>
<li>Optical thunderbolt cable plugged into the laptop</li>
<li>Thunderbolt cable connected to the PE4L</li>
<li>Power to the <a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00FMJPWFW">Sonnet Echo Express SE II</a> that powers the laptop fan and supplies power to the SATA / USB add in card and hard disk.</li>
<li>Power to the GPU via the ATX PSU</li>
</ol>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-top.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-top.jpg" alt="" class="lazyload fade-in" />
<figcaption>Top</figcaption>
</figure>
<ol>
<li><a href="https://www.amazon.com/dp/B00H707RP2/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00H707RP2">GPU</a></li>
<li>Small rubber pads to keep my laptop scratch free when placing it on top of the setup</li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm laptop fan</a></li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm GPU fan</a></li>
<li>Power to the GPU via the ATX PSU</li>
<li>Power to the <a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00FMJPWFW">Sonnet Echo Express SE II</a> and a <a href="https://www.amazon.com/dp/B005TWE5E6/" rel="nofollow" data-amazon-asin="[de]B0071IHQBK[us]B005TWE5E6">picoPSU-80</a> that powers the laptop fan and supplies power to the SATA / USB add in card and hard disk.</li>
</ol>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-front.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-front.jpg" alt="" class="lazyload fade-in" />
<figcaption>Front</figcaption>
</figure>
<ol>
<li><a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00FMJPWFW">Sonnet Echo Express SE II</a></li>
<li><a href="https://www.amazon.com/dp/B005TWE5E6/" rel="nofollow" data-amazon-asin="[de]B0071IHQBK[us]B005TWE5E6">picoPSU-80</a></li>
<li><a href="https://www.amazon.com/dp/B008Q7HUR0/" rel="nofollow" data-amazon-asin="[us]B008Q7HUR0[es][it][fr][ca][de][uk]B008O0ZKMQ">ATX PSU</a></li>
<li><a href="https://www.amazon.com/dp/B0080MQJJ6/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B0080MQJJ6">Sonnet Echo Express Adapter Pro</a> (Used for the PE4L, not plugged in the picture)</li>
<li>SSD</li>
<li><a href="https://www.amazon.com/dp/B00H707RP2/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00H707RP2">GPU</a></li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm laptop fan</a></li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm GPU fan</a></li>
</ol>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-left.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-left.jpg" alt="" class="lazyload fade-in" />
<figcaption>Left side</figcaption>
</figure>
<ol>
<li><a href="https://www.amazon.com/dp/B005TWE5E6/" rel="nofollow" data-amazon-asin="[de]B0071IHQBK[us]B005TWE5E6">picoPSU-80</a></li>
<li><a href="https://www.amazon.com/dp/B008Q7HUR0/" rel="nofollow" data-amazon-asin="[us]B008Q7HUR0[es][it][fr][ca][de][uk]B008O0ZKMQ">ATX PSU</a></li>
<li><a href="https://www.amazon.com/dp/B0080MQJJ6/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B0080MQJJ6">Sonnet Echo Express Adapter Pro</a>. Currently not connected to the PE4L to expand with the third pci-e slot</li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">200mm laptop fan</a></li>
</ol>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-back.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-back.jpg" alt="" class="lazyload fade-in" />
<figcaption>Back</figcaption>
</figure>
<p>No description, everything has been described in the previous pictures.</p>
<h4 id="the-modified-pci-e-riser">The modified pci-e riser</h4>
<p>I will not go into detail how I modified the PCI-E riser, but you can do the same following this <a href="https://www.techinferno.com/index.php?/forums/topic/2594-mac-mini-gtx660-echo-express-w7-black-screen/">post</a>. It basically cuts the 3 and 12 volt powerlines from the PCI-E slot and gets power directly from the PSU. It is only needed if you want to get the internal screen (Optimus) working under Windows 7. Windows 8 is plug and play, but only working to my knowledge on an external monitor.</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-pci-riser.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-pci-riser.jpg" alt="" class="lazyload fade-in" />
<figcaption>The modified PCI-E riser cable is visible in the middle of the picture</figcaption>
</figure>
<h4 id="the-25mm-dc-barrel-plug">The 2,5mm DC barrel plug</h4>
<p>I used a few of these to route the power from the Sonnet PSU to a picoPSU-80 which powers the fan under the laptop and supplies extra power to the SATA / USB add in card. I could have used the ATX PSU to power the whole thing, but since I plan to remotely power on and off the GPU only using a Belkin WeMo, then it was easier just to have separate PSU’s</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-barrel-plug.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-barrel-plug.jpg" alt="" class="lazyload fade-in" />
<figcaption>The power from the power brick is split between the Sonnet Echo Express SE II and the picoPSU-80 12V</figcaption>
</figure>
<h4 id="the-remote-control">The remote control</h4>
<p>From my previous posts it is written that you need to power cycle the GPU when rebooting the laptop. With the 10 meter cable that can be a pain to time it correctly. The solution is simple, a small remote control to control the wall socket I use for the ATX PSU which powers the GPU.</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-remote.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-remote.jpg" alt="" class="lazyload fade-in" />
<figcaption>Simple way to power cycle the GPU remotely</figcaption>
</figure>
<h3 id="software">Software</h3>
<p>With my previous setup I used a different and much more complex approach to install the software:</p>
<ul>
<li>Lenovo T430s (thunderbolt 1), see my previous post <a href="/projects/external-graphics-card-experiment-part-1">here</a></li>
<li>Macbook Pro Retina late 2013 (thunderbolt 2). See my previous posts about this <a href="/projects/egpu-rmbp-windows7-bios-nvidia-gtx-70-p4el">here</a> and <a href="/projects/egpu-osx-maverick-nvidia-gtx-70-using-pe4l">here</a></li>
</ul>
<p>When installing games to play that I know I will only play using the eGPU setup (3D intensive), I install them to the SSD connected to the eGPU setup to save space on my laptop drive.</p>
<p><strong>UPDATE 22-06-2014</strong><br />
Getting Optimus to work was quite easy once I found these two posts, <a href="https://www.techinferno.com/index.php?/forums/topic/5389-2013-15-mbp-iris-gtx76016gbps-tb2-sonnet-ee-se-ii-win-81-relentless/">here</a> and <a href="https://www.techinferno.com/index.php?/forums/topic/5420-updated-2013-13-or-15-macbook-pro-thunderbolt-2-egpu-plug-and-play-optimus/">here</a>. I used the <a href="http://www.microsoftstore.com/store/msusa/html/pbPage.Help_Win7_usbdvd_dwnTool">Windows 7 USB/DVD download tool</a> to create a bootable USB stick with Windows 8.1N, plugged it in and booted to the OS selection menu holding down the ALT key. I choose Windows USB and installed it to my previous bootcamp partition. I then followed the steps below taken from the above posts every time I want to get Optimus working. Install bootcamp and NVIDIA drivers when booting the first time. If the external GPU does not show up in device manager, make sure you make a <a href="http://www.thewindowsclub.com/force-full-shutdown-fully-reinitialize-windows-8">full shutdown</a> from Windows 8.1N and then try again.</p>
<blockquote>
<p>So I have worked out a repeatable process for getting my Optimus setup to work:</p>
<ol>
<li>Turn off Macbook.</li>
<li>Power off Sonnet (I actually pull the power out of the unit). This seems to reset the state of the Sonnet to clean.</li>
<li>Turn off power supply to GPU.</li>
<li>Power on Sonnet and plug in Thunderbolt cable.</li>
<li>Turn on laptop holding ALT/Option to allow OS selection.</li>
<li>When MacBook startup chime happens (a couple of seconds after power on) turn on GPU power supply.</li>
<li>Choose Windows from the OS selection menu.</li>
</ol>
<p>This works 3/3 times. I think the key learning is to make sure you turn off/unplug the Sonnet so any memory/state is lost from their board.</p>
<p>Of course, if you want to use an external screen then just turn off the MacBook and make sure the Sonnet and the GPU are powered and it will just work.</p>
</blockquote>
<p>The above steps have worked every time for the past few days. Notice that I don’t even need to use my bootcamp partition, I can install Windows 8.1N to my SSD connected to the eGPU setup to free even more space on the laptop.</p>
<p><strong>UPDATE 23-08-2014</strong><br />
After doing a reinstall I could not get both the SATA / USB card to work alongside the eGPU. If I pulled out the SATA / USB card and followed the above steps everything worked fine, with the SATA / USB card I got an error 12. To solve this problem I did a DSDT override using this <a href="https://www.techinferno.com/index.php?/forums/topic/5874-guide-dsdt-override-to-fix-error-12/#comment-91134">guide</a>, remember to enable test signing. When compiling the file you might get some errors, for my macbook pro 13 retina (late 2013 model) I got the error “syntax error, unexpected PARSEOP NOTIFY, expecting ‘,’ or ‘)’”. To solve this I changed the line with the error from</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>If (LEqual (PARM, 0x01))
{
Or (\_SB.PCI0.AUDE, 0x20, \_SB.PCI0.AUDE)
\_SB.PCI0.HDAU.ASTR (\_SB.PCI0.HDAU.AINI (\_SB.PCI0.HDAU.CXDC ()), Notify (\_SB.PCI0, 0x00))
}
</code></pre></div></div>
<p>to</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>If (LEqual (PARM, 0x01))
{
Or (\_SB.PCI0.AUDE, 0x20, \_SB.PCI0.AUDE)
\_SB.PCI0.HDAU.ASTR ()
\_SB.PCI0.HDAU.AINI ()
\_SB.PCI0.HDAU.CXDC ()
Notify (\_SB.PCI0, 0x00)
}
</code></pre></div></div>
<div class="notice danger no_toc_section">
<p><strong>A word of warning:</strong> I have no idea if my fix is the correct one, but it seems to be working fine and looks the same as <a href="http://pastebin.com/Mdqma8CS">here</a> (search for ‘HDAU.ASTR’)</p>
</div>
<p><strong>UPDATE 22-09-2014</strong><br />
After a major crash windows crash I could not the setup working again using the above steps. The one difference from I had was the default boot partition was bootcamp. I changed this back to OSX in the bootcamp control panel and then everything worked fine again</p>
<h3 id="the-final-product">The final product</h3>
<p><strong>Internal screen accelerated</strong><br />
Boot without a HDMI / DVI cable connected to the GPU and no external monitor connected using the thunderbolt docking station</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-laptop.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-laptop.jpg" alt="" class="lazyload fade-in" />
<figcaption>The laptop is getting cooled by the 200mm fan</figcaption>
</figure>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-corning-cable.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-corning-cable.jpg" alt="" class="lazyload fade-in" />
<figcaption>The setup hooked up to my work laptop in the living room</figcaption>
</figure>
<p><strong>Internal screen accelerated with external monitor connected through thunderbolt</strong><br />
Boot without a HDMI / DVI cable connected to the GPU and external monitor connected using the thunderbolt docking station. Now we have two displays, the internal one and external one, both accelerated.</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-T430s.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-T430s.jpg" alt="" class="lazyload fade-in" />
<figcaption>Lenovo T430s connected to the eGPU setup using the short cable…</figcaption>
</figure>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-dock.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-dock.jpg" alt="" class="lazyload fade-in" />
<figcaption>… and the long thunderbolt cable is connected to the eGPU setup and the CalDigit thunderbolt dock…</figcaption>
</figure>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-monitor.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-monitor.jpg" alt="" class="lazyload fade-in" />
<figcaption>… enabling a fully silent setup in the living room, fully controllable using a mouse and keyboard connected to the CalDigit thunderbolt dock!</figcaption>
</figure>
<p><strong>External monitor accelerated</strong>
Boot with HDMI / DVI cable connected to the eGPU. This gives the fastest performance, but the drawback on a Macbook Pro is that the internal GPU gets turned off so no internal monitor</p>
<figure>
<noscript><img src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-laptop-monitor.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l-laptop-monitor.jpg" alt="" class="lazyload fade-in" />
<figcaption>eGPU setup connected to an external monitor</figcaption>
</figure>
<p>One could use a long HDMI cable in conjunction with the 10m thunderbolt cable connected to the CalDigit thunderbolt dock to move the screen further away, but I prefer to use the previous example to only have a single cable even though I get a performance hit since the display signal takes some bandwidth from the thunderbolt cable. See the next section about performance
Here is a quickly, and badly, made video of the setup to give you an impression of the whole thing:</p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/2YkdGYEDUmY?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<h2 id="performance">Performance</h2>
<p>I do not expect 3DMark to increase, since bandwidth does not affect the benchmark much, see this <a href="http://www.techpowerup.com/reviews/Intel/Ivy_Bridge_PCI-Express_Scaling/21.html">post</a>. Therefore I also test using Unigine since it appears to be more bandwidth sensitive, see <a href="http://www.techpowerup.com/reviews/Intel/Ivy_Bridge_PCI-Express_Scaling/22.html">here</a></p>
<p>The following tests are executed using a 13 inch retina MacBook Pro late 2013 with 16 GB ram.</p>
<h3 id="unigine-valley-10-benchmark">Unigine Valley 1.0 benchmark</h3>
<p>Presets:</p>
<ul>
<li>Basic: 1280x720, DirectX 9, medium quality, 2x AA</li>
<li>Extreme: 1600x900, DirectX 11, ultra quality, 8x AA</li>
<li>Extreme HD: 1920x1080, DirectX 11, ultra quality, 8x AA</li>
</ul>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Basic</th>
<th style="text-align: right">Extreme</th>
<th style="text-align: right">Extreme HD</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100 - fps</td>
<td style="text-align: right">14,7</td>
<td style="text-align: right">5,0</td>
<td style="text-align: right">3,8</td>
</tr>
<tr>
<td>HD5100 - score</td>
<td style="text-align: right">616</td>
<td style="text-align: right">208</td>
<td style="text-align: right">160</td>
</tr>
<tr>
<td>GTX 760 (internal) - fps</td>
<td style="text-align: right">40,0</td>
<td style="text-align: right">40,3</td>
<td style="text-align: right">32,4</td>
</tr>
<tr>
<td>GTX 760 (internal) - score</td>
<td style="text-align: right">1674</td>
<td style="text-align: right">1686</td>
<td style="text-align: right">1354</td>
</tr>
<tr>
<td>GTX 760 (external) - fps</td>
<td style="text-align: right">85,4</td>
<td style="text-align: right">44,7</td>
<td style="text-align: right">35,3</td>
</tr>
<tr>
<td>GTX 760 (external) - score</td>
<td style="text-align: right">3575</td>
<td style="text-align: right">1870</td>
<td style="text-align: right">1479</td>
</tr>
</tbody>
</table>
<p>Using higher resolutions makes the difference between internal and external monitor using the GPU very small compared to lower resolutions or lower AA.</p>
<h3 id="3dmark">3DMark</h3>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Fire strike extreme</th>
<th style="text-align: right">Fire strike</th>
<th style="text-align: right">Sky diver</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100</td>
<td style="text-align: right">400</td>
<td style="text-align: right">921</td>
<td style="text-align: right">4077</td>
</tr>
<tr>
<td>GTX 760 (internal)</td>
<td style="text-align: right">2492</td>
<td style="text-align: right">4209</td>
<td style="text-align: right">8660</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">Cloud gate</th>
<th style="text-align: right">Ice storm extreme</th>
<th style="text-align: right">Ice storm</th>
</tr>
</thead>
<tbody>
<tr>
<td>HD5100</td>
<td style="text-align: right">5750</td>
<td style="text-align: right">36209</td>
<td style="text-align: right">46045</td>
</tr>
<tr>
<td>GTX 760 (internal)</td>
<td style="text-align: right">7975</td>
<td style="text-align: right">21411</td>
<td style="text-align: right">30124</td>
</tr>
</tbody>
</table>
<p>Notice that the level entry test “Ice storm” is faster using the internal GPU, this is most likely a bandwidth issue. Where the setup really shines is the heavier benchmarks like Fire strike.</p>
<p><em>On my to-do list is testing higher resolutions using external monitors, the highest tested is 1080p. I don’t own any monitor that has higher resolution than 1080p</em></p>
<h2 id="noise">Noise</h2>
<p>All measurements were made 10 cm from the eGPU setup using the iPhone app Decibal. Not an accurate way, but gives you a ballpark estimate of the noise.</p>
<ul>
<li>42 dB idle, both 200mm fans on low</li>
<li>44 dB idle, both 200mm fans on medium</li>
<li>49 dB idle, both 200mm fans on high</li>
</ul>
<p>This is without the GPU fans spinning at full speed. I expect to able to reduce the noise by disabling the GPU fans and only letting the 200mm fan cool the card. Of course with a 10m optical thunderbolt cable you can completely eliminate any noise from the eGPU setup by moving the laptop to another room.</p>
<p>Or even better, eliminate the noise from the eGPU and laptop by leaving the laptop connected with the short 0,5m thunderbolt cable and using the second thunderbolt port on the eGPU docking station to connect the 10m thunderbolt cable to the CalDigit thunderbolt. The CalDigit thunderbolt has HDMI, 3 USB ports, Ethernet, audio and microphone and a secondary thunderbolt port, enabling completely silent gaming setup!</p>
<p>See the video below to see the setup with an idle GPU and the fans set to low, then in the middle of the video set to high.</p>
<div class="responsive-video-container"><iframe width="640" height="360" data-src="https://www.youtube-nocookie.com/embed/ILtODgFA6r8?showinfo=0" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen="" class="lazyload"></iframe></div>
<h2 id="price">Price</h2>
<p>The price of the <a href="https://www.amazon.com/dp/B00FMJPWFW/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00FMJPWFW">Sonnet Echo Express SE II</a> is 500 USD. This is twice as much as my old setup which consisted of the PE4L (70 USD) and the <a href="https://www.amazon.com/dp/B0080MQJJ6/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B0080MQJJ6">Sonnet Echo Express Adapter Pro</a> (170 USD) = 240 USD. If you need to save money, that is one way to go, but you get one quarter of the bandwidth which might not be enough for you. You can get the cheaper <a href="https://www.amazon.com/dp/B00IPSJLXG/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B00IPSJLXG">Sonnet Echo Express SEL</a> for 350 USD on Amazon which only have a single PCI-E slot, but it is still thunderbolt 2. The cheapest way is to skip thunderbolt altogether and just get the PE4Lfor 70 USD, but is requires your laptop to have an pci express port.</p>
<p>If you want an estimate of the total cost, you need to look up the price on the parts list earlier in the post.</p>
<h2 id="whats-next">Whats next?</h2>
<ul>
<li>Eliminate the picoPSU and Sonnet power supply and take all power from the ATX power supply driving the GPU. Implement a switch to be able cut off power to the 12v lines to the GPU alone.</li>
<li>When sitting 10 meters away, the timing of turning the GPU on and off is difficult. To mitigate this, I plan to purchase a remote-controlled power outlet so I can turn the ATX psu on and off using my cellphone, something like the <a href="https://www.amazon.com/dp/B01DBXNYCS/" rel="nofollow" data-amazon-asin="[ca][us]B01DBXNYCS[es][it][fr][de][uk]B00EPQB1LC">Belkin WeMo Insight Switch</a></li>
<li>One could add more PCI-E ports, sharing the PCI-E 2.0 x4 bandwidth using a PCI-E splitter, something like the one from <a href="http://amfeltec.com/products/flexible-x4-pci-express-4-way-splitter-gpu-oriented/">Amfeltec</a>. This is very low on my list since I have 3 slots already</li>
<li>PCI-E bandwidth for GPU does not increase performance much when going from PCI-E 2.0 x2 to PCI-E 2.0 x16, see this <a href="http://www.techpowerup.com/reviews/Intel/Ivy_Bridge_PCI-Express_Scaling/18.html">post</a>. There is room for another GPU, a SLI setup using two cards, each having PCI-E 2.0 x2 performance, should be faster than my current setup with a single GPU at PCI-E 2.0 x4. While SLI performance itself might be nice, using a SLI setup on an older thunderbolt 1 laptop should give the same performance as a thunderbolt 2 laptop, since the bandwidth in thunderbolt 1 and 2 is the same, except that thunderbolt 1 can only use 10 Gbit/s per device, up to a total of 20 Gbit/s. A SLI setup should take advantage of the full bandwidth of thunderbolt 1!</li>
<li>While thunderbolt 3 promises twice the speed of thunderbolt 2, around PCI-E 2.0 x8 speeds, I have no desire to upgrade anytime soon since the increase of bandwidth is not increasing performance by much. Maybe in a few years</li>
<li>At some point I might consider using 3mm acrylic to cover up the case so its less open and less exposed. The massive 200mm fans should still be able to cool the setup</li>
</ul>
<p>That was my brief description of my eGPU setup, leave a comment if you have any questions</p>
<p><strong>UPDATE 20-08-2014</strong><br />
<em>Added a 3DMark benchmark (iGPU and eGPU using the internal monitor only, but it adds some high resolution benchmarks. Also added a secondary harddisk</em></p>
<p><strong>UPDATE 01-04-2015</strong><br />
<em>I would not recommend this setup anymore, a cheaper and better setup can be seen in my blog post <a href="/projects/thunderbolt-2-egpu-setup-using-akitio-thunder2">here</a> if you just need it for attaching a single graphics card</em></p>
<p><a href="https://odd-one-out.serek.eu/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l/" rel="nofollow">eGPU using Sonnet Echo Express SE II</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Thunderbolt 2 eGPU built around the Sonnet Echo Express SE II and PE4L using a custom built open air case.eGPU with Windows 7 (BIOS), NVIDIA, PE4L & Sonnet TB adapter2014-04-02T00:00:00+00:002014-04-02T19:21:00+00:00https://odd-one-out.serek.eu/projects/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el
<p><img src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_detect_GPU-feature.jpg" alt="" /></p>
<p>This post describes how to get the card working in Windows 7 (BIOS / Bootcamp install) which includes getting Optimus to work (read: Accelerating the internal screen of the laptop). This is mostly getting the software to work, my hardware setup is described more <a href="/projects/external-graphics-card-experiment-part-1">here</a>.</p>
<h2 id="setup">Setup</h2>
<ol>
<li>Boot into OS X</li>
<li>Use Boot Camp to create a bootable USB stick from a Windows 7 image, including the drivers</li>
<li>Reboot and install Windows 7. If you keep booting into OS X, then reboot and hold down the “ALT” key until you see a boot menu where the USB stick should be selectable. Alternatively use a boot manager like <a href="http://www.rodsbooks.com/refind/">rEFInd</a></li>
<li>Update Windows until nothing can be updated</li>
<li>Purchase and download <a href="https://egpu.io/diy-egpu-setup-1-30-nando4/">DIY eGPU Setup 1.x</a></li>
<li>Extract the files to <code class="highlighter-rouge">C:/eGPU</code></li>
<li>As admin run <code class="highlighter-rouge">C:/eGPUsetup-disk-image.bat</code> and follow the instructions</li>
</ol>
<figure>
<noscript><img src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Setup_Install_Screen.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Setup_Install_Screen.png" alt="" class="lazyload fade-in" />
</figure>
<ol start="8">
<li>Run <code class="highlighter-rouge">C:/eGPUeGPU-Setup-mount.bat</code> to mount the disk image</li>
<li>Replace <code class="highlighter-rouge">V:/configpci.bat</code> with the one from part C <a href="https://www.techinferno.com/index.php?/forums/topic/3225-2013-11-mba-gtx5704gbpsc-tbec2-pe4l-21b-win7-kloper/">here</a>. I could not generate anything that I could get to work with DIY eGPU</li>
<li>Turn of the laptop, turn off the GPU</li>
<li>Plug in eGPU setup with SW1 set to 3 and SW2 set to 2-3</li>
<li>Make sure no monitor is connected to the eGPU</li>
<li>Turn on the GPU</li>
<li>Turn on the laptop while holding down the “ALT” key and choose to boot windows</li>
<li>Select “DIY Setup 1.x” in the windows boot menu</li>
</ol>
<figure>
<noscript><img src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Windows_boot_menu.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Windows_boot_menu.jpg" alt="" class="lazyload fade-in" />
</figure>
<ol start="16">
<li>Wait for the automated startup</li>
</ol>
<figure>
<noscript><img src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Menu.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Menu.jpg" alt="" class="lazyload fade-in" />
</figure>
<ol start="17">
<li>Wait for the automatic detection of the GPU</li>
</ol>
<figure>
<noscript><img src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_detect_GPU.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_detect_GPU.jpg" alt="" class="lazyload fade-in" />
</figure>
<ol start="18">
<li>This time let it boot into windows</li>
</ol>
<figure>
<noscript><img src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Windows_boot_menu_2.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el-DIY_Windows_boot_menu_2.jpg" alt="" class="lazyload fade-in" />
</figure>
<ol start="19">
<li>Install NVIDIA drivers if needed</li>
</ol>
<h2 id="performance">Performance</h2>
<p>I did not do any performance testing since I just replaced my laptop with one that was more difficult getting to work on the software side. The performance should be very similar to the one I got in <a href="/projects/external-graphics-card-experiment-part-1">this post</a></p>
<h2 id="limitations">Limitations</h2>
<ol>
<li>Using a DSDT override it should not be necessary to use DIY eGPU setup. I did do this, but no success in getting the eGPU to work even though the “large memory” did shown up correctly.</li>
</ol>
<h2 id="what-is-next">What is next?</h2>
<p>The next project is to make a better and faster docking station using the Sonnet Echo Express SE II which will increase my bandwidth 4 times compared to this setup. It will include an onboard SSD drive and a pair of USB ports so I can boot of the external SSD when using the graphics cards at home. This way I free up much-needed space on the laptop since games and other files only needed when connected to the GPU can stay in the docking station. I will have to get creative with a pci-e riser since this the Sonnet does not have a pci-e reset delay needed for this setup to work.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="http://www.futuremark.com/benchmarks/3dmark/all">3DMark</a></li>
<li><a href="http://www.geeks3d.com/gputest/">Geeks3D GpuTest</a></li>
<li><a href="https://egpu.io/diy-egpu-setup-1-30-nando4/">DIY eGPU setup 1.x</a></li>
<li><a href="http://www.rodsbooks.com/refind/">rEFInd boot manager</a></li>
<li><code class="highlighter-rouge">pci.bat</code> used in DIY Setup from <a href="https://www.techinferno.com/index.php?/forums/topic/3225-2013-11-mba-gtx5704gbpsc-tbec2-pe4l-21b-win7-kloper/">here</a> (part C)</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/egpu-rmbp-windows7-bios-nvidia-gtx-760-p4el/" rel="nofollow">eGPU with Windows 7 (BIOS), NVIDIA, PE4L & Sonnet TB adapter</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/External GPU: Retina MacBook Pro with Windows 7 (BIOS) and NVIDIA GTX 760 using PE4L with Sonnet adapter.eGPU with OS X 10.9, NVIDA GPU, PE4L & TB adapter2014-02-24T00:00:00+00:002014-02-24T07:00:00+00:00https://odd-one-out.serek.eu/projects/egpu-osx-maverick-nvidia-gtx-760-using-pe4l
<p>A while ago I made an external GPU setup described <a href="/projects/external-graphics-card-experiment-part-1/">here</a>. Now I have replaced my Lenovo T430s laptop with a MacBook pro 13 retina (late 2013 model) and worked on getting the card to work under both Windows 7, Windows 8.1 and OS X. This post describes how to get the card working in OS X 10.9 (Maverick)</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<p>The setup used a <a href="https://www.amazon.com/dp/B00GWM5ZLO/" rel="nofollow" data-amazon-asin="[de][es][it][fr]uk[ca][uk][uk]B00GWM5ZLO">Bplus PE4L</a>, <a href="https://www.amazon.com/dp/B0080MQJJ6/" rel="nofollow" data-amazon-asin="[us][de][ca][it][es][fr]B0080MQJJ6">Sonnet Echo ExpressCard Pro Thunderbolt</a> adapter and a <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=NVIDIA+GTX+760" rel="nofollow">NVIDIA GTX 760</a> graphics card.
If you have a Thunderbolt enabled device I now recommend the <a href="https://www.amazon.com/dp/B00LTAUTHE/" rel="nofollow" data-amazon-asin="[us][ca]B00LTAUTHE[uk]B00OQPWE72[de][es][it][fr]B00NQ23TCU">AKiTiO Thunder2</a> as described in my post <a href="/projects/thunderbolt-2-egpu-setup-using-akitio-thunder/">here</a>.</p>
<h2 id="setup">Setup</h2>
<ul>
<li>Should already be installed, else use recovery to reinstall</li>
<li>Boot into OS X</li>
<li>Open the terminal</li>
<li>Edit the following <code class="highlighter-rouge">Info.plist</code> files using the “sudo nano {path/filename}” command
<ol>
<li><code class="highlighter-rouge">/System/Library/Extensions/NVDAStartup.kext/Contents/Info.plist</code></li>
<li><code class="highlighter-rouge">/System/Library/Extensions/IONDRVSupport.kext/Info.plist</code></li>
<li><code class="highlighter-rouge">/System/Library/Extensions/AppleHDA.kext/Contents/PlugIns/AppleHDAController.kext/Contents/Info.plist</code></li>
</ol>
</li>
<li>
<p>In each of the above files find each section starting with</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><key></span>CFBundleIdentifier<span class="nt"></key></span>
</code></pre></div> </div>
<p>and add</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><key></span>IOPCITunnelCompatible<span class="nt"></key></span>
<span class="nt"><true/></span>
</code></pre></div> </div>
<p>just before the corresponding closing <code class="highlighter-rouge"></dict></code> of the section. Example of the modified <code class="highlighter-rouge">/IONDRVSupport.kext/Info.plist</code> is shown here. The <code class="highlighter-rouge">CFBundleIdentifier</code> section can be seen on line 45, 62 and 79 and their corresponding <code class="highlighter-rouge">IOPCITunnelCompatible</code> entries at 57-58, 74-75 and 91-92.</p>
</li>
</ul>
<figure class="highlight"><pre><code class="language-xml" data-lang="xml"><table class="rouge-table"><tbody><tr><td class="gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
</pre></td><td class="code"><pre><span class="cp"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="cp"><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"></span>
<span class="nt"><plist</span> <span class="na">version=</span><span class="s">"1.0"</span><span class="nt">></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>BuildMachineOSBuild<span class="nt"></key></span>
<span class="nt"><string></span>13A3014<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleDevelopmentRegion<span class="nt"></key></span>
<span class="nt"><string></span>English<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleExecutable<span class="nt"></key></span>
<span class="nt"><string></span>IONDRVSupport<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleGetInfoString<span class="nt"></key></span>
<span class="nt"><string></span>2.4, Copyright Apple Computer, Inc. 2000-2012<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleIdentifier<span class="nt"></key></span>
<span class="nt"><string></span>com.apple.iokit.IONDRVSupport<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleInfoDictionaryVersion<span class="nt"></key></span>
<span class="nt"><string></span>6.0<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleName<span class="nt"></key></span>
<span class="nt"><string></span>I/O Kit NDRV Support<span class="nt"></string></span>
<span class="nt"><key></span>CFBundlePackageType<span class="nt"></key></span>
<span class="nt"><string></span>KEXT<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleShortVersionString<span class="nt"></key></span>
<span class="nt"><string></span>2.4<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleSignature<span class="nt"></key></span>
<span class="nt"><string></span>????<span class="nt"></string></span>
<span class="nt"><key></span>CFBundleVersion<span class="nt"></key></span>
<span class="nt"><string></span>2.4<span class="nt"></string></span>
<span class="nt"><key></span>DTCompiler<span class="nt"></key></span>
<span class="nt"><string></span>com.apple.compilers.llvm.clang.1_0<span class="nt"></string></span>
<span class="nt"><key></span>DTPlatformBuild<span class="nt"></key></span>
<span class="nt"><string></span>5A11344p<span class="nt"></string></span>
<span class="nt"><key></span>DTPlatformVersion<span class="nt"></key></span>
<span class="nt"><string></span>GM<span class="nt"></string></span>
<span class="nt"><key></span>DTSDKBuild<span class="nt"></key></span>
<span class="nt"><string></span>13A3014<span class="nt"></string></span>
<span class="nt"><key></span>DTSDKName<span class="nt"></key></span>
<span class="nt"><string></string></span>
<span class="nt"><key></span>DTXcode<span class="nt"></key></span>
<span class="nt"><string></span>0500<span class="nt"></string></span>
<span class="nt"><key></span>DTXcodeBuild<span class="nt"></key></span>
<span class="nt"><string></span>5A11344p<span class="nt"></string></span>
<span class="nt"><key></span>IOKitPersonalities<span class="nt"></key></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>1<span class="nt"></key></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>CFBundleIdentifier<span class="nt"></key></span>
<span class="nt"><string></span>com.apple.iokit.IONDRVSupport<span class="nt"></string></span>
<span class="nt"><key></span>IOClass<span class="nt"></key></span>
<span class="nt"><string></span>IONDRVFramebuffer<span class="nt"></string></span>
<span class="nt"><key></span>IOMatchCategory<span class="nt"></key></span>
<span class="nt"><string></span>IOFramebuffer<span class="nt"></string></span>
<span class="nt"><key></span>IONameMatch<span class="nt"></key></span>
<span class="nt"><string></span>display<span class="nt"></string></span>
<span class="nt"><key></span>IOProbeScore<span class="nt"></key></span>
<span class="nt"><integer></span>20000<span class="nt"></integer></span>
<span class="nt"><key></span>IOProviderClass<span class="nt"></key></span>
<span class="nt"><string></span>IOPCIDevice<span class="nt"></string></span>
<span class="nt"><key></span>IOPCITunnelCompatible<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"></dict></span>
<span class="nt"><key></span>2<span class="nt"></key></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>CFBundleIdentifier<span class="nt"></key></span>
<span class="nt"><string></span>com.apple.iokit.IONDRVSupport<span class="nt"></string></span>
<span class="nt"><key></span>IOClass<span class="nt"></key></span>
<span class="nt"><string></span>IONDRVFramebuffer<span class="nt"></string></span>
<span class="nt"><key></span>IOMatchCategory<span class="nt"></key></span>
<span class="nt"><string></span>IOFramebuffer<span class="nt"></string></span>
<span class="nt"><key></span>IONameMatch<span class="nt"></key></span>
<span class="nt"><string></span>display<span class="nt"></string></span>
<span class="nt"><key></span>IOProbeScore<span class="nt"></key></span>
<span class="nt"><integer></span>20000<span class="nt"></integer></span>
<span class="nt"><key></span>IOProviderClass<span class="nt"></key></span>
<span class="nt"><string></span>IOPlatformDevice<span class="nt"></string></span>
<span class="nt"><key></span>IOPCITunnelCompatible<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"></dict></span>
<span class="nt"><key></span>3<span class="nt"></key></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>CFBundleIdentifier<span class="nt"></key></span>
<span class="nt"><string></span>com.apple.iokit.IONDRVSupport<span class="nt"></string></span>
<span class="nt"><key></span>IOClass<span class="nt"></key></span>
<span class="nt"><string></span>IONDRVFramebuffer<span class="nt"></string></span>
<span class="nt"><key></span>IOMatchCategory<span class="nt"></key></span>
<span class="nt"><string></span>IOFramebuffer<span class="nt"></string></span>
<span class="nt"><key></span>IOPCIClassMatch<span class="nt"></key></span>
<span class="nt"><string></span>0x03000000<span class="ni">&amp;</span>0xff000000<span class="nt"></string></span>
<span class="nt"><key></span>IOProbeScore<span class="nt"></key></span>
<span class="nt"><integer></span>0<span class="nt"></integer></span>
<span class="nt"><key></span>IOProviderClass<span class="nt"></key></span>
<span class="nt"><string></span>IOPCIDevice<span class="nt"></string></span>
<span class="nt"><key></span>IOPCITunnelCompatible<span class="nt"></key></span>
<span class="nt"><true/></span>
<span class="nt"></dict></span>
<span class="nt"></dict></span>
<span class="nt"><key></span>OSBundleCompatibleVersion<span class="nt"></key></span>
<span class="nt"><string></span>1.0.0b1<span class="nt"></string></span>
<span class="nt"><key></span>OSBundleLibraries<span class="nt"></key></span>
<span class="nt"><dict></span>
<span class="nt"><key></span>com.apple.iokit.IOGraphicsFamily<span class="nt"></key></span>
<span class="nt"><string></span>1.1<span class="nt"></string></span>
<span class="nt"><key></span>com.apple.iokit.IOPCIFamily<span class="nt"></key></span>
<span class="nt"><string></span>1.1<span class="nt"></string></span>
<span class="nt"><key></span>com.apple.kpi.iokit<span class="nt"></key></span>
<span class="nt"><string></span>8.0.0<span class="nt"></string></span>
<span class="nt"><key></span>com.apple.kpi.libkern<span class="nt"></key></span>
<span class="nt"><string></span>8.0.0<span class="nt"></string></span>
<span class="nt"><key></span>com.apple.kpi.mach<span class="nt"></key></span>
<span class="nt"><string></span>8.0.0<span class="nt"></string></span>
<span class="nt"><key></span>com.apple.kpi.unsupported<span class="nt"></key></span>
<span class="nt"><string></span>8.0.0<span class="nt"></string></span>
<span class="nt"></dict></span>
<span class="nt"><key></span>OSBundleRequired<span class="nt"></key></span>
<span class="nt"><string></span>Safe Boot<span class="nt"></string></span>
<span class="nt"></dict></span>
<span class="nt"></plist></span></pre></td></tr></tbody></table></code></pre></figure>
<ul>
<li>Type “sudo touch /System/Library/Extensions”</li>
<li>Wait a few minutes until the extension cache is rebuild. You can check the activity monitor the kext cache rebuild process, sort after CPU usage</li>
<li>Shutdown the laptop</li>
<li>Plug in eGPU setup with SW1 set to 1 and SW2 set to 2-3</li>
<li>Connect the eGPU to an external monitor and make sure the monitor is on</li>
<li>Boot into OS X</li>
<li>My GPU is already supported by OS X (NVIDIA GTX 760) so no driver installation needed</li>
<li>Change from mirroring the display to extending the desktop</li>
<li>You should now have a working setup, the internal screen is functional as is the external, but only the external screen is accelerated</li>
</ul>
<h2 id="performance">Performance</h2>
<p>I use Geeks3D GpuTest with everything standard settings except resolution which is set to 1440x900 windowed mode.</p>
<table>
<thead>
<tr>
<th> </th>
<th style="text-align: right">FurMark</th>
<th style="text-align: right">TessMark (X8/X8)</th>
<th style="text-align: right">GiMark</th>
</tr>
</thead>
<tbody>
<tr>
<td>Internal screen (Intel HD 5100) - score</td>
<td style="text-align: right">698</td>
<td style="text-align: right">6863</td>
<td style="text-align: right">1420</td>
</tr>
<tr>
<td>Internal screen (Intel HD 5100) - fps</td>
<td style="text-align: right">11</td>
<td style="text-align: right">114</td>
<td style="text-align: right">23</td>
</tr>
<tr>
<td>External monitor (NVIDIA GTX 760) - score</td>
<td style="text-align: right">5313</td>
<td style="text-align: right">74793</td>
<td style="text-align: right">6734</td>
</tr>
<tr>
<td>External monitor (NVIDIA GTX 760) - fps</td>
<td style="text-align: right">88</td>
<td style="text-align: right">1247</td>
<td style="text-align: right">112</td>
</tr>
<tr>
<td><strong>Improvement</strong></td>
<td style="text-align: right"><strong>761%</strong></td>
<td style="text-align: right"><strong>1089%</strong></td>
<td style="text-align: right"><strong>474%</strong></td>
</tr>
</tbody>
</table>
<h2 id="limitations">Limitations</h2>
<ol>
<li>The internal screen is not accelerated, only the external monitor. Using Optimus this should be possible, worked fine on my Lenovo T430s using Windows, I need to investigate this further.</li>
<li>Only unplug the thunderbolt cable when the computer is off, else a kernel panic will occur.</li>
<li>Need to power the GPU and laptop off before plugging the eGPU in and the monitor must be connected to the eGPU and powered on</li>
</ol>
<h2 id="references">References</h2>
<ul>
<li>Enable GPU through thunderbolt by editing kext files taken from this <a href="http://www.journaldulapin.com/2013/08/24/a-thunderbolt-gpu-on-a-mac-how-to/">post</a></li>
<li><a href="http://www.geeks3d.com/gputest/">Geeks3D GpuTest</a></li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/egpu-osx-maverick-nvidia-gtx-760-using-pe4l/" rel="nofollow">eGPU with OS X 10.9, NVIDA GPU, PE4L & TB adapter</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Getting en external eGPU working with OS X 10.9 using the PE4L with Sonnet adapter.Using google adwords to increase free Dropbox space2014-02-16T00:00:00+00:002014-02-16T18:00:00+00:00https://odd-one-out.serek.eu/projects/using-google-adwords-to-increase-free-dropbox-space
<p><img src="/assets/images/using-google-adwords-to-increase-free-dropbox-space-campaign-feature.png" alt="" /></p>
<p>A few years ago I stumbled upon this article</p>
<p><a href="http://lifehacker.com/5854955/how-to-max-out-your-dropbox-referrals-with-google-adwords-for-free">http://lifehacker.com/5854955/how-to-max-out-your-dropbox-referrals-with-google-adwords-for-free</a></p>
<p>describing how to get free Dropbox space by using google adwords to make people click on your referral link to Dropbox. Each click and installation of Dropbox gives you free space up to a certain amount.
My experience is that you can only advertise in USA and Canada since you are allowed to use the word “dropbox” in your ad and link. In Denmark you can no longer get coupons for free adwords credit, but you can pay a certain amount, 200 DKK, and get a coupon for 800 DKK which is only useable for a new adwords account (about a week old) that has not used a coupon before. But that should in my experience be enough to get two dropbox accounts fully maxed out on referrals.</p>
<figure>
<noscript><img src="/assets/images/using-google-adwords-to-increase-free-dropbox-space-campaign-feature.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/using-google-adwords-to-increase-free-dropbox-space-campaign-feature.png" alt="" class="lazyload fade-in" />
<figcaption>Example of my Dropbox campaign as it would look on google and its bid configuration</figcaption>
</figure>
<p>My settings can be downloaded and imported using the official adwords editor to get you started:</p>
<p>Editor: <a href="http://www.google.com/intl/en/adwordseditor/">http://www.google.com/intl/en/adwordseditor/</a><br />
Settings: <a href="https://odd-one-out.serek.eu/wp-content/uploads/2014/02/DropboxGoogleAdwordsCampaign2014-01-07.csv?dl=1">DropboxGoogleAdwordsCampaign2014-01-07.csv</a></p>
<p>Play around the price per click values and max daily spending limit. Lower per click values means cheaper prices, but longer time before your ad gets shown, if at all.</p>
<p><strong>UPDATE (19-02-2014)</strong><br />
If you use my settings, remember to change the actual referral link with your own, else you will not get any referrals.</p>
<p><a href="https://odd-one-out.serek.eu/projects/using-google-adwords-to-increase-free-dropbox-space/" rel="nofollow">Using google adwords to increase free Dropbox space</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/Running a Google AdWords campaign to increase your Dropbox space - for free!Cryptocurrency mining: Bitcoin, Litecoin and more2014-01-12T00:00:00+00:002014-01-12T19:00:00+00:00https://odd-one-out.serek.eu/projects/cryptocurrency-mining-bitcoin-litecoin-and-more
<p><img src="/assets/images/cryptocurrency-mining-bitcoin-logo-feature.png" alt="" /></p>
<p>You might have heard about digital currency called Bitcoin in the news. The value from a single Bitcoin has grown from a few dollars to 1200 USD and recently back to 1000 USD, a highly volatile currency.</p>
<figure>
<noscript><img src="/assets/images/cryptocurrency-mining-Bitstamp-BTC_USD-BitcoinWisdom.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-Bitstamp-BTC_USD-BitcoinWisdom.png" alt="" class="lazyload fade-in" />
<figcaption>Bitcoin value in USD over time - from BitcoinWisdom.com</figcaption>
</figure>
<p>It is open source, distributed, decentralised and uses cryptographic principles for securing the setup. For more information about this, please see:</p>
<p><a href="http://bitcoin.org/en/">http://bitcoin.org/en/</a><br />
<a href="http://en.wikipedia.org/wiki/Cryptocurrency">http://en.wikipedia.org/wiki/Cryptocurrency</a><br />
<a href="http://en.wikipedia.org/wiki/Litecoin">http://en.wikipedia.org/wiki/Litecoin</a></p>
<figure>
<noscript><img src="/assets/images/cryptocurrency-mining-bitcoin-logo.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-bitcoin-logo.png" alt="" class="lazyload fade-in" />
<figcaption>Bitcoin logo</figcaption>
</figure>
<p>Some highlights of Bitcoin usage that has caught the public:</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Silk_Road_%28marketplace%29">Silk Road</a> - The Amazon of illegal drugs</li>
<li><a href="http://www.forbes.com/sites/andygreenberg/2013/11/18/meet-the-assassination-market-creator-whos-crowdfunding-murder-with-bitcoins/">Assassination Market</a> - A website that crowd-funds murder</li>
<li><a href="https://bitcoinatm.com/">Bitcoin ATM</a> - Deposit or withdraw Bitcoins</li>
<li><a href="http://app.bitlaundry.com/">Bitcoin laundery</a> - Send money anonymously</li>
<li><a href="http://www.cnbc.com/id/100597242">Cyprus crisis</a></li>
<li>Chinese government crackdown on Bitcoin</li>
</ul>
<p>To get started using Bitcoins one can download a Bitcoin wallet, like <a href="https://multibit.org/">MultiBit</a> or use an online wallet service like blockchain.info. Keep your wallet secure and keep backups, there are no central bank to help you if you get hacked, hard disk breaks down or you forget your password. A Bitcoin address looks like this (my donation address):</p>
<p><strong>343m5YhZ7y78WokLVqHDFC6K2k896sWCNw</strong></p>
<p>Which nobody can remember, with smartphone technology you can use you camera to scan QR codes representing the address and additional information. For this you can use the blockchain.info iPhone or android app.</p>
<figure class="gallery-2-col">
<a href="/assets/images/cryptocurrency-mining-QR-donate.png"><noscript><img src="/assets/images/cryptocurrency-mining-QR-donate.png" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-QR-donate.png" alt="QR code to transfer to Bitcoin address" class="lazyload fade-in" /></a>
<a href="/assets/images/cryptocurrency-mining-QR-donate-0.005.png"><noscript><img src="/assets/images/cryptocurrency-mining-QR-donate-0.005.png" /></noscript><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-QR-donate-0.005.png" alt="QR code to donate 0.005 BTC" class="lazyload fade-in" /></a>
<figcaption>QR code for 343m5YhZ7y78WokLVqHDFC6K2k896sWCNw with (right) and without (left) a preset amount of 0.005 BTC</figcaption>
</figure>
<p>To actually purchase some Bitcoins you can use online services which normally involves sending cash to their bank account since most do not accept credit cards. If you live in Denmark I recommend BitcoinNordic, i have used them and it works. They have a high commission rate of 4.9 percent and you cannot choose at what rate you would like to buy the Bitcoins. BitcoinNordic uses another exchange Bitstamp.net, here the fees are much lower. I use this exchange myself, more on this later in the post.
Bitcoin is just one of many cryptocurrencies, but it is the first and most integrated of them all. Now, why is this so interesting besides potentially revolutionising currency as we know it? From wikipedia:</p>
<blockquote>
<p>Within cryptocurrency systems, the safety, integrity, and balance of all ledgers is ensured by a swarm of mutually distrustful parties, referred to as miners, who are, for the most part, general members of the public, actively protecting the network by maintaining a high hash-rate difficulty for their chance at receiving a randomly distributed small fee.
Basically, by using your computer with an internet connection you can join these networks and get a small amount of cryptocurrency which then again can be exchanged for “real” money, like USD or euros. With the correct price for electricity, cryptocurrency and difficulty in mining you can make actual money.</p>
</blockquote>
<figure>
<noscript><img src="/assets/images/cryptocurrency-mining-litecoin-logo.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-litecoin-logo.png" alt="" class="lazyload fade-in" />
<figcaption>Litecoin logo</figcaption>
</figure>
<p>I have become one of these miners for a cryptocurrency called Litecoin and similar alternative currencies, which allows me to use standard graphics cards to make a profit “generating” these coins, trading them for Bitcoins, trading Bitcoins for USD, which is then converted via EURO to Danish Kroners in my bank account.</p>
<h2 id="hardware-setup">Hardware setup</h2>
<p>For Litecoin mining I have bought four AMD Radeon graphic cards since these are most effective in mining Litecoins and other scrypt based cryptocurrency compared to Nvidia cards (see <a href="https://litecoin.info/Mining_hardware_comparison">https://litecoin.info/Mining_hardware_comparison</a>, performance is measured in kilohashes per second). Why not mine Bitcoin directly? This is because bitcoin using a different algorithm, SHA256, which now requires specialised hardware, ASIC (Application-specific integrated circuit), to have a chance to make any money.</p>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<ul>
<li>4x <a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=Radeon+7950" rel="nofollow">Club3D Radeon 7950</a> graphic cards ~ 1190 USD</li>
<li><a href="https://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias%3Daps&field-keywords=Corsair+AX1200" rel="nofollow">Corsair AX1200</a> 1200 watt powersupply ~ 330 USD</li>
<li>4GB DDR3 memory ~ 60 USD</li>
<li>Intel Celeron G470 CPU ~ 52 USD</li>
<li>4x Powered PCI-E 1x - 16x Riser Cable with Molex ~ 35 USD</li>
<li><a href="https://www.amazon.com/dp/B007QWIA9S/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B007QWIA9S">MSI Z77A-G45</a> motherboard ~ 125 USD</li>
<li><a href="https://www.amazon.com/dp/B000V6FKGM/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B000V6FKGM">2x 200mm case fans</a> ~ 55 USD</li>
<li>1x 8 mm case fan ~ 10 USD</li>
<li>Old SSD harddisk</li>
</ul>
<p>Total ~ 1850 USD
The setup is a bit improvised, the graphic cards are tied to a 18 USD IKEA computer desk I have bought, the motherboard and SSD hard disk are laying on a piece of broken garden fence and I have connected an old computer case to this setup so I can use the start and reset buttons to operate the system.</p>
<figure>
<noscript><img src="/assets/images/cryptocurrency-mining-litecoin-mining.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-litecoin-mining.png" alt="" class="lazyload fade-in" />
<figcaption>Litecoin mining setup… not pretty, but it works!</figcaption>
</figure>
<p>The total power used by this system measured from the wall socket is 975 watt.</p>
<h2 id="software-setup">Software setup</h2>
<p>I run windows 8.1 since it was easier for me to tweak my graphics cards, else Linux would be a better choice in my opinion. To tweak the graphics cards I use a program called Trixx to set each card with the following settings:</p>
<ul>
<li>GPU clock: 1050</li>
<li>Memory clock: 1475</li>
<li>VDDC: 1.087</li>
<li>Fan: Manual at 100%</li>
</ul>
<p>I use CGMiner v3.7.2 which is the last version to support GPU mining, the config file can be found <a href="/assets/files/cryptocurrency-mining/cgminer.conf">here</a>.
Since I did not have time to setup my router with VPN, I did a quick and dirty way of remote controlling the setup, introducing Dropbox remote management! Here is what I did:</p>
<ul>
<li>I setup windows to execute the bat file <code class="highlighter-rouge">AutoRun.bat</code> every minute</li>
<li><code class="highlighter-rouge">AutoRun.bat</code> simply calls <code class="highlighter-rouge">CGMinerAutoStart.bat</code> and renames itself to <code class="highlighter-rouge">AutoRunExecuted.bat</code> to prevent further executing by the windows timer job</li>
<li>C<code class="highlighter-rouge">GMinerAutoStart.bat</code> kills any running instances of CGMiner.exe, deletes the generated binary files from CGMiner and sets some global settings. It then calls <code class="highlighter-rouge">cgminer.bat</code> which starts the mining process again</li>
</ul>
<p>By editing the CGMiner config file I can change setting and mining pools easy. By logging to a directory in my dropbox folder I can see the output from CGMiner to confirm it is running correctly. To restart CGMiner after changes has been made I just rename <code class="highlighter-rouge">AutoRunExecuted.bat</code> to <code class="highlighter-rouge">AutoRun.bat</code> and wait.
All the mentioned bat files can be downloaded <a href="/assets/files/cryptocurrency-mining/CGMiner_batfiles.zip">here</a></p>
<p>One quirk I have noticed is that when rebooting the machine, the three graphic cards that are not connected to my monitor, stay in a low power state so performance is very low. I need to manually plug the DVI cable into each card and wait for a signal for the to “wake up”. I have tried using dummy VGA to DVI plugs, but it did not help. Any suggestions is appreciated.</p>
<h2 id="performance">Performance</h2>
<p>Each card runs at 600 kilohashes per second, a total of 2.4 megahashes per second. With overclocking I could get further, but the cost in power (energy efficiency drops the warmer it gets), heat and noise would increase. It is important to hit the correct ration between the core and memory to get extra performance, if anyone got some suggestions for these Club3D cards, please contact me.</p>
<figure>
<noscript><img src="/assets/images/cryptocurrency-mining-CGMiner.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-CGMiner.jpg" alt="" class="lazyload fade-in" />
<figcaption>My CGMiner performance</figcaption>
</figure>
<h2 id="noise-and-heating">Noise and heating</h2>
<p>Four graphics cards running full speed generates some noise and heat. With the door closed to the room containing the setup, the noise is minimal, standing in the same room however and the noise is quite loud. I have relatively low temperatures on the graphic cards, around 60 degrees Celsius, so I could tweak the cooling to lower the noise, but have not found the time. The small room gets very warm fast with the door closed, so I use this trick to get the best of both worlds</p>
<figure>
<noscript><img src="/assets/images/cryptocurrency-mining-heating-solution.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/cryptocurrency-mining-heating-solution.jpg" alt="" class="lazyload fade-in" />
<figcaption>Using the Danish winter to cool the setup when not home</figcaption>
</figure>
<ul>
<li>When at home, I close the door to the room containing the setup to minimize noise. To prevent the graphics card to get to warm and therefore use more electricity / automatically lower performance to prevent overheating I open the door to the balcony. Danish winter cools the room nicely :)</li>
<li>When leaving the home I close the door to the balcony and open the door to my living room. The setup generates enough heat to keep the apartment nice and warm when I get back</li>
</ul>
<p>The noise measurements are as follows (using an iPhone app, not super accurate):</p>
<ul>
<li>Inside room with setup (3 feet from setup): 61 dB</li>
<li>Outside the room right next to the door: 44 dB</li>
<li>From sofa 15 feet away from door: 41 dB</li>
</ul>
<p>On my to-do list is to isolate the door a bit more and if the noise turns out to be too much, then I will move the setup outside on the balcony in some weatherproof enclosure.</p>
<h2 id="from-cryptocurrency-to-actual-money-in-my-bank-account">From cryptocurrency to actual money in my bank account</h2>
<p>The output of my mining setup is scrypt based coins, like Litecoin (LTC), Dogecoin (DOGE) and Worldcoin (WDC). I mine these coins by joining a mining pool to share the work and the rewards. These mining pools even out the need for luck and provides a consistent payout of coins. Mining pools typically have small fees, around 0 - 3% of the coins awarded. The mining pools I use are:</p>
<ul>
<li>Coinotron - For mining Litecoin (LTC), but has support for other coins</li>
<li><a href="https://www.multipool.us/">Multipool</a> - Automatically mines the most profitable coin</li>
</ul>
<p>Multipool uses and algorithm similar to the following sites to take into account difficulty of mining, reward size and value when calculating profit.</p>
<ul>
<li><a href="http://www.coinwarz.com/cryptocurrency">CoinWarz</a></li>
<li>CoinChoose</li>
</ul>
<div class="notice danger no_toc_section">
<p><strong>A word of caution</strong> when using mining profitability calculators found on many of these sites. Most do not take into account the constant rise in mining difficulty, which can be several percent a day! So take that into consideration if you want to get into the mining business.</p>
</div>
<p>Next step is transferring them to an exchange so we can trade them to Bitcoins (BTC) or any other coin we choose. I look at past values and try to sell them at a good price which might take days or I might choose to hold on to the coins and hope the price will go up later. The market is quite volatile so there is money to be made by speculating in this. I use these exchanges</p>
<ul>
<li>Coinedup - No trading fees, I use it to trade Dogecoin (DOGE) into Bitcoins (BTC)</li>
<li><a href="http://blog.cryptsy.com/">Cryptsy</a> - Up to 0.3 percent trading fee, trades between many cryptocurrencies. Optional autotrade can be enabled for an additional 0.1 percent</li>
<li><a href="http://bitstamp.net/">Bitstamp.net</a> - Up to 0.5 percent trading fee, trades between Bitcoins (BTC) and USD</li>
</ul>
<p>When I want to sell my coins for real money, like USD or EURO I transfer my Bitcoins to Bitstamp. Typically there is a small withdrawal fee to get coins out of the exchanges. To transfer USD to my bank account I need to be authorized by Bitstamp by supplying them with a picture ID and proof of residence. It costs 0.9 EURO + 20 Danish Kroners my bank charges to withdraw money to my bank account which arrives after a week. A total of about 10 USD per withdrawal.</p>
<h2 id="economy">Economy</h2>
<p>I have made the following with my setup running 39 days and my initiation investment of 275 USD into Bitcoins. This is actual uptime my setup has had, the three days downtime I had I subtracted, since no power was used (it rained into my wall socket on the balcony, turned off all power!):</p>
<table>
<thead>
<tr>
<th>Expenses</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Hardware setup</td>
<td>$1.850</td>
</tr>
<tr>
<td>Bitcoin investment</td>
<td>$275</td>
</tr>
<tr>
<td>Wireless internet</td>
<td>$14</td>
</tr>
<tr>
<td>Powerbill (975 watt)</td>
<td>$399</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$2.537</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Income</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Return on Bitcoin investment</td>
<td>$640</td>
</tr>
<tr>
<td>Cryptocurrency sold</td>
<td>$256</td>
</tr>
<tr>
<td>Cryptocurrency held in wallets</td>
<td>$634</td>
</tr>
<tr>
<td>Sale of spare parts leftover</td>
<td>$73</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$1.604</td>
</tr>
</tbody>
</table>
<p><strong>Profit:</strong> <font color="red">-$934</font></p>
<p>If I sell my hardware for half price, then I will break even on everything. I will let the setup run for another month or two and see where it takes me. As you can see, the power cost I substantial here in Denmark, 399 USD, and it generated 256 + 634 = 890 USD. If I had access to very cheap or free power, then my profit would increase 50%. With the increasing difficulty in mining one would expect a decline in profit, but with the volatile market prices it is hard to tell.
Now as the good citizen I am I have contacted the Danish tax authority about paying taxes of my profit (if I even get a profit) and they kindly replied that they will respond within 3 months with an answer. For now I consider this a hobby business (“Hobbyvirksomhed” in Danish) which means I have to pay taxes of my profit when I get it.</p>
<p><strong>– UPDATE 08-05-2014 —</strong></p>
<p>I let the setup run for a total of 80 days before I shut it down, here are the updated results:</p>
<table>
<thead>
<tr>
<th>Expenses</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Hardware setup</td>
<td>$1.850</td>
</tr>
<tr>
<td>Bitcoin investment</td>
<td>$275</td>
</tr>
<tr>
<td>Wireless internet</td>
<td>$31</td>
</tr>
<tr>
<td>Powerbill (975 watt)</td>
<td>$764</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$2.920</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Income</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Return on Bitcoin investment</td>
<td>$640</td>
</tr>
<tr>
<td>Cryptocurrency sold</td>
<td>$1.491</td>
</tr>
<tr>
<td>Cryptocurrency held in wallets</td>
<td>$8</td>
</tr>
<tr>
<td>Sale of spare parts leftover</td>
<td>$75</td>
</tr>
<tr>
<td>Sale of 4 GPU</td>
<td>$1.109</td>
</tr>
<tr>
<td><strong>Total</strong></td>
<td>$3.323</td>
</tr>
</tbody>
</table>
<p><strong>Profit:</strong> $402</p>
<p>In addition to the above $402 in profit I have hardware leftover for $577.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I am happy with my setup, i have currently generated enough money to pay for the experiment if i sell the setup for half price, got free heating during Danish winter and have quenched my curiosity of cryptocurrency.
My recommendation to others is:</p>
<ul>
<li>Never invest more than you are willing to lose. Cryptocurrency is volatile and could be worthless any second</li>
<li>While mining cryptocurrency is fun to try, you might not make enough money to pay for the equipment. If you already own the hardware try it, but if not consider starting out taking advantage of the volatile market.</li>
<li>Take backups and do not keep too much money in a single wallet</li>
<li>If you have a girlfriend, wife or roommate, consider that the noise might be disturbing</li>
</ul>
<p><a href="https://odd-one-out.serek.eu/projects/cryptocurrency-mining-bitcoin-litecoin-and-more/" rel="nofollow">Cryptocurrency mining: Bitcoin, Litecoin and more</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/My adventures in cryptocurrency mining - and yes, you can make a small profit!External graphics card experiment: Part 12014-01-07T00:00:00+00:002014-05-25T19:48:00+00:00https://odd-one-out.serek.eu/projects/external-graphics-card-experiment-part-1
<p><img src="/assets/images/external-graphics-card-experiment-part-1-eGPU-setup-overview-feature.png" alt="" /></p>
<p>I always wanted to have a small light portable computer on the go and when I get home to use a docking station and get the full desktop experience. Following other people examples on the internet I have made this cheap solution with and external graphics card in the docking station (eGPU) that can be used with an external monitor or accelerate the internal screen of the laptop.</p>
<h2 id="parts">Parts</h2>
<!-- Affiliate disclamer removed because of GDPR and removal of affiliate links -->
<div class="notice"><h3>Disclaimer</h3>This post contains links to Amazon where I get a small commission if you purchase anything after clicking on these links - at no extra cost to you! But only if you have explicitly consented to this. I have purchased all the mentioned products myself and I only link to products that I believe are the best for my readers. If you want to help out even more, take a look <a href="/support/">here</a>.</div>
<ul>
<li>Laptop with thunderbolt port (Lenovo T430s)</li>
<li>Graphics card (<a href="https://www.amazon.com/dp/B00DGM8B6O/" rel="nofollow" data-amazon-asin="[de][uk]B00H707RP2[us][es][it][fr][ca]B00DGM8B6O">GIGABYTE Nvidia GTX 760</a>) ~ 275 USD</li>
<li>PCI-E 1x to ExpressCard adapter <a href="https://www.amazon.com/dp/B00GWM5ZLO/" rel="nofollow" data-amazon-asin="[de][es][it][fr]uk[ca][uk][uk]B00GWM5ZLO"">PE4L-EC060</a>) ~ 70 USD + 22 USD postal fees</li>
<li><a href="https://www.amazon.com/dp/B0080MQJJ6/" rel="nofollow" data-amazon-asin="[de][uk][us][es][it][fr][ca]B0080MQJJ6">Sonnet Echo Express Thunderbolt Adapter Pro</a> ~ 120 USD</li>
<li>Thunderbolt cable ~ 55 USD</li>
<li>ATX power supply ~ 73 USD</li>
<li>Case ~ 75 USD</li>
</ul>
<p>That is 415 USD for the setup without the laptop and graphics card and 690 USD with the graphics card included. Notice all prices are in USD but I live in Denmark so prices are higher than the states.</p>
<h2 id="setup">Setup</h2>
<p>My laptop is connected via thunderbolt to the Sonnet Echo Thunderbolt to ExpressCard adapter which is connected to the PCI-E 1x ExpressCard adapter. I connect the graphics card to this PCI-E 1x port, the power supply unit and case.</p>
<figure>
<noscript><img src="/assets/images/external-graphics-card-experiment-part-1-eGPU-setup-overview.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-experiment-part-1-eGPU-setup-overview.png" alt="" class="lazyload fade-in" />
<figcaption>Final eGPU setup</figcaption>
</figure>
<figure class="gallery-2-col">
<noscript><img src="/assets/images/external-graphics-card-experiment-part-1-back.jpg" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-experiment-part-1-back.jpg" alt="" class="lazyload fade-in" />
<figcaption>Closeup of GPU inside the case</figcaption>
</figure>
<p>The setup is configured to start when the laptop start or wakes from sleep and turns off when the computer turns off. I have installed windows 7 64 bit. I have not used any bootloaders, memory reallocation or third-party tools like described <a href="https://www.techinferno.com/index.php?/forums/topic/3225-2013-11-mba-gtx5704gbpsc-tbec2-pe4l-21b-win7-kloper/">here</a>.
Maybe it is because I don’t use MacBook in combination with bootcamp. My laptop does not contain a discrete graphics card which might have helped me avoid PCI memory allocation problems. When I plugin the cable it detects my graphic card and I install the drivers.</p>
<h2 id="performance">Performance</h2>
<p>There are two ways of using the setup, one is to display the content on an external monitor connected to the graphic card. Another is to accelerate the laptops internal monitor, I give you performance measurements for both:</p>
<h3 id="3dmark-6">3dMark 6</h3>
<ul>
<li>21028 with NVIDIA GeForce GTX 760(1x) and Intel Core i7-3520M (external monitor</li>
<li>18829 with NVIDIA GeForce GTX 760(1x) and Intel Core i7-3520M (internal laptop screen)</li>
<li>6678 with Intel HD Graphics 4000 Mobile(1x) and Intel Core i7-3520M (internal laptop screen)</li>
</ul>
<p>Looking at the first part of the test I saw these framerates:</p>
<ul>
<li>GeForce GTX 760 (external monitor) 160 fps</li>
<li>GeForce GTX 760 (internal laptop monitor) 100 fps</li>
<li>Intel HD Graphics 4000 Mobile (internal laptop monitor) 30 fps</li>
</ul>
<h3 id="3dmark11">3dMark11</h3>
<figure>
<noscript><img src="/assets/images/external-graphics-card-experiment-part-1-3dmark11-hd4000.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-experiment-part-1-3dmark11-hd4000.png" alt="" class="lazyload fade-in" />
<figcaption>Laptop only, internal laptop screen</figcaption>
</figure>
<figure>
<noscript><img src="/assets/images/external-graphics-card-experiment-part-1-3dmark11-gtx760.png" /></noscript>
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/assets/images/external-graphics-card-experiment-part-1-3dmark11-gtx760.png" alt="" class="lazyload fade-in" />
<figcaption>External monitor, external graphics card</figcaption>
</figure>
<p>I did not take a screenshot of the test using the internal laptop screen and the external graphics card, but the score was 4400.</p>
<h2 id="scaling">Scaling</h2>
<p>Using an ExpressCard adapter halves the bandwidth of thunderbolt 1, so the effective bandwidth is PCI-E 2.0 x1. This does slow down the graphics performance, but not as much as you might think:</p>
<p><a href="http://www.techpowerup.com/reviews/Intel/Ivy_Bridge_PCI-Express_Scaling/1.html">http://www.techpowerup.com/reviews/Intel/Ivy_Bridge_PCI-Express_Scaling/1.html</a></p>
<p>Using a laptop with the new thunderbolt 2 port and a setup that support this thunderbolt port, like enclosures from Sonnet or Magma, would have a bandwidth of PCI-E 2.0 x4, four times as much, but not four times the performance. See my post about my thunderbolt 2 setup <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l">here</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>I have succeeded in building a setup that is close to giving my the full desktop experience, with some performance limitations. Why not just buy a desktop pc on the side? Well I still only want a single computer, not two, even if the performance is reduced. Next project however is getting a laptop with two thunderbolt 2 ports (MacBook Pro retina 13 inch) and Sonnet Echo Express SE II so I can enjoy the full PCI-E 2.0 x4 speed and with a possibility to use two graphics card if I use PCI-E risers and an external power supply. Corning has just released 33 feet optical thunderbolt cables which enables all the noisy hardware to be further away from me. But that is another blog post when the money is there</p>
<p><strong>UPDATE 08-01-2014:</strong> Added pictures of the setup</p>
<p><strong>UPDATE 25-05-2014:</strong> Upgraded the setup to thunderbolt 2, see my post <a href="/projects/thunderbolt-2-egpu-built-around-sonnet-echo-express-se-ii-and-pe4l">here</a></p>
<p><a href="https://odd-one-out.serek.eu/projects/external-graphics-card-experiment-part-1/" rel="nofollow">External graphics card experiment: Part 1</a> was originally published on Odd One Out.</p>
Poul Serekhttps://Ox3.serek.eu/about/External graphics card connected via Thunderbolt using the PE4L-EC060 ExpressCard adapter and Sonnet Echo Express Thunderbolt Adapter Pro.