This is a short portfolio of significant works I have done over the past few years. Clicking on the tiles will open a popup with more details about the work. Some of the tiles also have a link to code samples, 3D designs, or other relevant materials.
Please contact me for further details about any of the projects listed below. You can also find me on Facebook, Twitter (@UriShX), and on Hackcady.io. You can also email me at: urish[at]urishx[dot]com
The Github repo for this portfolio is: UriShX/Jekyll-portfolio. A markdown portfolio that was the basis for starting this project lives here.
Realization of a product design, POC for a graduation project exhibition. Nitinol heated stems for paper flowers, lit by LEDs, in a faux vase. Animation of the flowers by resistively heating the NiTi wires and PWM control of the LEDs brightness. Design by my wife, Aya Shani, as grduation project in product design at H.I.T..
Design for plastic injection molding: UAV fuel tank.
Material selection, redesign of costumer’s basic design concept, inc. mechanical and Moldflow FAE, mold design approval and parts approval.
Salaried work for Supergum, as principal design engineer, for security sector costumer.
A working model prototype for usability testing of a sound box in a plush toy which is under development.
Usability tested for sound box size, operation and ease of use, and loudness.
Contract work.
An ESP32 based kitchen scale for bread baking. Connects to Google sheets over WiFi to retrieve bread formulas, and to save measured weight of ingredients.
BLE serves to define WiFi, as well as display current measurement.
Calculates baker’s percentage on the fly.
Mechanical and electrical design, along with programming. Creating a working installation from the artist’s concept. Construction in collaboration with Studio Omri Ben Artzi, for the exhibition “Data Mining”, Shachar Marcus, MUZA, 2019.
A web-ble responsive web app to demonstrate control over BLE of ESP32 projects.
Includes links to github repo of web app, and to a couple of ESP32 sketches for testing.
This web app uses web-ble to control a esp32 device over ble, while subscribing to its’ updates, and includes ‘autoranging’.
App is designed to work with esp32 ble controlled apps, see breathing LED gist and Hobby servo gist.
App is deployed at https://urishx.github.io/ESP32_fader/.
TODO
There’s currently no documentation and little to no code remarks in the web app.
However, The Arduino sketches in the attached Gists are commented pretty well.
There are probably better ways to implement this web-ble web app. It was just a quick test for myself, and as such was not taken too seriously.
On the UI side, I should probably define several portrait orientation widths, and move the slider accordingly. Right now it is not positioned correctly on all devices.
On the UX side, I should probably ditch the slider alltogether, and replace it with something that will not cause accidental refreshes.
I started making this app a PWA, but never quite figured it out completley. It can and should be done.
Mechanical design, characterization and selection of drive mechanism / motor, production of shop drawings, supervision on construction. Produced in collaboration with studio Omri Ben Artzi, as an installation in the exhibition “Data Mining”, Shachar Marcus, MUZA, 2019.
Mechanical design. Design a working mechnical system from the artist’s concept. Construction in collaboration with the artist, for exhibition. Riki Stollar, 2020.
A touch sensitive PCB name card I designed for myself.
Design of the card was meant as playground in which to play around with PCB art, ATtiny13, and some blinking LEDs, while maintaining a balance between playfulness, usability, and low cost.
#!/usr/bin/env python3
# A short python script to play once a video file when button is pressed
# meant to run on Raspberry Pi, with button connected to GPIO 21
# script meant to be used in a commercial exhibition, and button to be pressed by PMMA "coin"
# inserted to slot in arcade-styled enclosure.
# Sample video from https://peach.blender.org/download/
# Requires omxplayer!!
importRPi.GPIOasGPIOimportosimportsysfromomxplayer.playerimportOMXPlayerfrompathlibimportPathfromtimeimportsleepGPIO.setmode(GPIO.BCM)# button on GPIO 21
GPIO.setup(21,GPIO.IN,pull_up_down=GPIO.PUD_UP)# indication LED on GPIO 13
GPIO.setup(13,GPIO.OUT)# DEBUG button on GPIO 24
#GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_UP)
VIDEO_PATH=Path("/home/pi/mu_code/videos/SampleVideo_1280x720_10mb.mp4")iflen(sys.argv)>1:VIDEO_PATH=Path(sys.argv[1])player=OMXPlayer(VIDEO_PATH,args='--no-osd --no-keys -b -o hdmi')defplayerExit(code):player.quit()print('exit',code)os._exit(0)last_state1=Trueinput_state1=Truequit_video=Falsetimer=0playing=False# set variable for length of video
videoLength=player.duration()-0.1# after loading pause at end of video
sleep(videoLength)player.pause()GPIO.output(13,0)whileTrue:#Read states of input
input_state1=GPIO.input(21)#If GPIO(21) is shorted to Ground
ifinput_state1!=last_state1:if(notplayingandnotinput_state1):player.set_position(0)player.play()GPIO.output(13,1)playing=Trueifplaying:iftimer>(videoLength-0.01):print("Video flie length: %f, Timer: %f"%(videoLength,timer))timer=0player.pause()GPIO.output(13,0)playing=Falseelse:timer+=player.position()/1000.0player.exitEvent+=lambda_,exit_code:playerExit(exit_code)#GPIO(24) to close omxplayer manually - used during debug
ifquit_video==True:# pygame.quit()
player.quit()os.system('killall omxplayer.bin')playing=Falsesys.exit(0)os._exit(-1)break#Set last_input states
last_state1=input_state1
A web based app used to configure WiFi credentials over Bluetooth LE (BLE), for esp32 based IoT projects. Check it out here.
The app is written in NuxtJS, a Vue framework for server side rendered apps. This is a recreation of the app, which was originally written using KnockoutJS and JQuery. The main reason for recreating the app was that having the BLE configuration and connection parts as Nuxt / Vue Components can help integrate them further into more complex web applications.
The app interacts with the esp32 using web-bluetooth, which is a web standard under development. Thus, it is available atm (02/2020) only on Chrome browsers, on OSX Yosemite and later, Windows 10, Linux with required bluez version etc., and Android > 6.0. Click here for current implementation status
Requirements
The app relies on communication with a esp32 based device / dev board, set up to support configuration of mutiple APs over BLE. Check it out here.
The Arduino script can be found at: https://github.com/UriShX/esp32_wifi_ble_advanced, written in PlatformIO (with the Arduino framework). The esp32 app complements this web app in functionality, and supports writing, reading, as well as both WiFi connection status and a list of access points seen by the esp32 device.
The communication with the esp32 device is based on Bernd Giesecke’s ESP32 WiFi configuration over BLE, and intends to replace the native Android Java app Bernd used. It also expands on Bernd’s original use to support connection status reporting and passing a list of SSIDs seen by the esp32.
Sadly, there is no support atm for iOS devices, though I believe it can be possible to achieve with nativescript.
The app does not allow the user to change the visibility of passwords recieved from the esp32 device, as well as accessing the passwords from the console using elment access. Control of this feature is done in InputPair.vue.
The Arduino sketch for the esp32 requires both SSID and password to be set, for both the primary and secondary fields. Validation is set to require all fields to have content, unless “Configure Secondary SSID” is set to OFF and both the secondary SSID and password fields are blank (and the primary ones have content) - in which case the primary fields’ content will be copied to the secondary. This scheme can be configured in Config.vue.
The communication between the esp32 device and the app is slightly obfuscated by doing a XOR operation of the stringified JSON object with the esp32 device’s name. The operation occurs on both the recieve and send operations, and can be found in string_helpers.js, and its calling functions in Config.vue.
The app uses the UUIDs Bernd Giesecke’s used in his original app to maintain backward compatibility.
The app searches only for devices with a name that starts with “ESP32”, and does not display other devices.
geo_spoof.js is used to prevent the BLE connection from asking permission to use geolocation services. App still requests location services on Android.
Android v. 6.0 and above requires ACCESS_COARSE_LOCATION to be allowed,and geo_spoof.js is an attempt to mitigate that by providing a false location in order for the app to work even when geolocation cannot be found by the Android device. More info about this subject can be found in this dicussion on stackoverflow.com. I have not tested it on this particular app, but have used this method with success to control a servo over BLE in a basement with no GPS reception for another web app.
navigatorCheck.js contains the method used to check the users’ OS and browser for compatibilty with the web-bluetooth standard.
Disabling a “No JavaScript” alert and checking browser and OS for compatibilty is done in Compatibility.vue.
Build Setup
Bluetooth-LE requires a secure connection over HTTPS. For development, the nuxt.config.js file contains links to server key and certificate files, according to Nuxt’s documentation. The files should either be stored in ~/ssl/, or the server tag in nuxt.config.js should be edited to fit. server.host is also set as 0.0.0.0, to allow testing and debugging on connected Android device through local network.
This app was set up to be deployed to github pages, according to Nuxt’s guide. Since the app was built to be static, the generate.subFolders property in nuxt.config,js was set to false, to generate separate files for each of the pages. The dist folder is white-listed in .gitignore, and can be easily pushed to gh-pages branch. More details can be found here.
# install dependencies$ npm install# serve with hot reload at localhost:3000$ npm run dev
# build for production$ npm run build
# generate static project for github pages deployment$ npm run generate:gh-pages
# push dist folder to github pages$ git subtree push --prefix dist origin gh-pages
For detailed explanation on how things work, check out Nuxt.js docs.
TODO
Check geolocation spoofing. Android still requests turning on location services, and in testing returns the function from geo_spoof.js. Not sure if the values are accepted by the navigator. This should be checked in an environment where geolocation is not available, such as a basement.
Approval of molded products produced by “Supergum” as contracted work.
Parts were approved according to customer’s requirements, and were collaboratively designed with a leading design studio.
Mechanical FEA of plastic injection molded concrete pouring pot, first step in approval for customer’s design.
Salaried work for “Supergum”, for a customer manufacturing land stabilizing solutions.
As part of my salaried work for Supergum, I was involved in design and design for manufacture of multiple elastomer parts.
As part of my work there I was involved in elastomeric material selection, advising customers on design decisions, and fitting processes and technologies for particular products.
-ash shell script for getting the recommended NordVPN server, downloading said server’s OpenVPN config file, setting credentials, and configuring OpenWRT for using said server.
Description
The script is meant to be run either from the command line (once), or from crontab as a scheduled task.
By running the script from the command line once with the desired parameters (country, server group, and connection protocol), a recommended VPN server profile is retrieved and set as the active OpenVPN profile.
By running the script from a crontab with the desired parameters, users can maintain the optimal connection to the desired server country and group combination with the required protocol. This can be done by scheduling the script to run once per hour, for example.
By using crontab, it is also possible to schedule connection to different VPN servers at certain times in a day or in a week.
The script outputs both error messages and normal operation log messages using OpenWRT’s logger, using the -s flag. That means log messages are both logged in the system log, as well as seen displayed to the user when running from CLI.
The script scrubs unused profiles by removing them from the OpenWRT OpenVPN configuration and deleting the respective .ovpn files.
The reason for saving at least the last used profile is that from my experience, sometimes a recommended server is actually too busy to operate reliably. In that case, switching to the last known good profile provides a good alternative, giving the opportunity to request a different server once again. This should probably be written in a script that’ll replace NordVPN’s keep-alive script.
Only the currently used and the previous profiles are kept on the device. An additional option for keeping more profiles on the device is planned, using regular expressions as the option’s parameter.
The countries in which NordVPN operates servers, and the server groups are retrieved from this repository, in the db branch.
The group-countries.tsv table displays the possible combinations.
The db branch is configured to be updated every 15 minutes by a Github action. In practice, the Github scheduling (for free repositories at least) runs the action at best once an hour. Not ideal, but until I figure out a better filtering system that doesn’t require installing JQ (~93 kB) on the router, scraping NordVPN’s API on a remote machine seems like a better approach for the meantime. Please notice: It appears that the API lists different servers at different times, so re-check if you couldn’t get to the servers you wanted to connect to.
About server groups and server group + country combinations
NordVPN does not provide OpenVPN profiles ready to download for all groups, and does not provide every server groups in each country. This means that for some queries to the NordVPN API will return empty, and for others a .ovpn configuration file will not be downloaded. In those cases the script should fail gracefully with failure messages printed to system log, as well as to the terminal when running the script from CLI.
The best way to figure out if your parameters will actually work is to check the group-countries.tsv table, which is set up to be scraped every 15 minutes (doesn’t really work on schedule, but about once an hour seems good enough).
I noticed some recommended server for group and country combinations from NordVPN server recommendation site did not show up in my scraped tables. Since the script downloads and connections are based on queries to NordVPN’s API, and the tables the script queries are also scraped from the same API, I did not try to fix that.
Of course, it is also possible to try the group + country combination from the script’s CLI.
Server groups known to work, with countries in which there are servers of that group, with OpenVPN profiles
Title
Remarks
Works in the following countries
Double_VPN
-
CA, CH, FR, GB, HK, NL, SE, TW, US
Onion_Over_VPN
Shaky, usually returns only one
(NL, CH)
Dedicated_IP
Depends on purchase of dedicated IP?
DE, GB, NL, US
Standard_VPN_servers
-
AT, AU, BA, BE, BG, CA, CH, CY, CZ, DE, DK, ES, FR, GB, GR, HR, HU, IL, IT, JP, LU, LV, MY, NL, NO, PL, RO, SK, UA, US, VN, ZA
P2P
-
AT, AU, BA, BE, BG, CA, CH, CZ, DE, DK, ES, FR, GB, GR, HR, HU, IL, IT, JP, LU, LV, NL, NO, PL, RO, SK, US, ZA
Regional groups
Title
Countries in region
Europe
AT, BA, BE, CH, CY, CZ, DE, DK, FR, GB, HR, HU, NL, NO, PL, SE
The_Americas
CA, US
Asia_Pacific
AU, HK, ID, JP, MY, NZ, SG, TW, VN
Africa__the_Middle_East_and_India
IL, IN, TR, ZA
Special Thanks
Writing this script would not have been possible without the exquisite NordVPN API documentation by Milosz Galazka.
Installation
The script relies on OpenWRT’s (BusyBox) built-in wget and jsonfilter, but depends on several other packages. Check how much free space you have on your device either from LuCI (system -> software) or from shell by running df and looking at the /overlay line. You can compare the space left to the list of requirements below.
Follow (if you haven’t already) NordVPN’s guide for setting up OpenVPN on your router, and make sure your router connects to NordVPN’s servers and your internet connection is good.
Log in to your router’s shell, eg.: ssh root@192.168.1.1.
Run the following command on your remote shell to check whether wget can be used to send GET requests: wget -O - "https://raw.githubusercontent.com/urishx/vpn-profile-switcher/db/countries.tsv"
If you get a table of countries in which NordVPN has servers, you’re all set, skip to the last step to download the script to your router.
In case the response you you got was: wget: SSL support not available, please install one of the libustream-.*[ssl|tls] packages as well as the ca-bundle and ca-certificates packages.
you will need to install libustream*tls* and its dependencies. - Run opkg update - Then opkg list libustream* - Look for libustream-.*tls.*, copy the package name, and install it by running opkg install <the-package-name-you-copied>.
eg.: opkg install libustream-mbedtls20150806 on my TP-Link Archer C20i w/ OpenWRT v19.07.5. - Re-check step 3, to see you now get the table of countries.
Downloading the script and first run:
Run wget https://raw.githubusercontent.com/UriShX/vpn-profile-switcher/main/vpn-profile-switcher.sh to download the script to your router.
Run chmod +x vpn-profile-switcher.sh.
Test the script by running ./vpn-profile-switcher.sh.
Requirements
From NordVPN’s guide (~800 kB with required dependencies):
openvpn-openssl (~158.4 kB)
ip-full (~167.4 kB)
luci-app-openvpn (~12.2 kB)
tls for executing GET requests using wget (~180 kB):
libustream-mbedtls20150806 (~4.5 kB)
libmbedtls12 (~178 kB)
Switching script, profiles, etc. (~14 kB):
vpn-profile-switcher.sh (~8 kB)
2 OpenVPN profile - current and last used (ea. ~2.8)
Usage
Run ./vpn-profile-switcher.sh -h to list the available parameters:
vpn-profile-switcher.sh v1.0.0
Get NordVPN recommended profile and set OpenVPN on OpenWRT to use said profile.
Usage: ./vpn-profile-switcher.sh [options ]
Options:
-h | –help, Print this help message
-p | –protocol < udp | tcp >, Select either UDP or TCP connection. Default is UDP.
-c | –country < code | name >, Select Country to filter by. Default is closest to your location.
-g | –group < group_name >, Select group to filter by.
-l | –login-info < filename >, Specify file for VPN login credentials. Default is ‘secret’.
For more information see README in repo: https://github.com/UriShX/vpn-profile-switcher
Script parameters
-p or --protocol
Has to be followed by either udp or tcp (lowercase).
Select either UDP or TCP connection.
If protocol is not defined, the script assumes UDP, for a faster (though less secure) connection.
For some details about the up and down sides of both TCP and UDP, see this article.
-c or --country
Has to be followed by either the country’s ID, code, or name (ignores case).
Select country to filter by.
Default is closest to your location as determined by NordVPN’s server, so if you are connected to a server which is far from your actual location and do not specify a different location for the script to filter by, your location will be remain in the same location as the server you are connected to.
You can view the list of available countries here.
-g or --group
Has to be followed by desired server group’s ID, identifier, or title.
Select group to filter by.
Unlike the --country filter, the group has to be specified with every request. According to NordVPN’s documentation, connecting to P2P services will be re-routed through either Canada or Holland, while Onion over VPN is only available through specific servers.
In short - the default server to which you will be will most likely be a standard server. Read more here.
You can view the list of available server groups here.
-l or --login-info
Has to be followed by filename.
Specify file for VPN login credentials.
Default is ‘secret’, as in NordVPN’s guide for setting a connection with OpenWRT over OpenVPN.
Examples
From CLI
Connect to a recommended Peer to Peer (P2P) server in the United States over UDP (default protocol)
# ./vpn-profile-switcher.sh -c US -g p2p
Output:
root: (./vpn-profile-switcher.sh) Arguments: Protocol: udp; Country: 228; NordVPN group: legacy_p2p; User credentials: secret.
root: (./vpn-profile-switcher.sh) Fetching VPN recommendations from: https://api.nordvpn.com/v1/servers/recommendations?filters[servers_groups][identifier]=legacy_p2p&filters[country_id]=228&filters[servers_technologies][identifier]=openvpn_udp&limit=1
root: (./vpn-profile-switcher.sh) Recommended server URL: us6739.nordvpn.com.
root: (./vpn-profile-switcher.sh) Fetching OpenVPN config us6739.nordvpn.com.udp.ovpn, and setting credentials pointing to: secret
root: (./vpn-profile-switcher.sh) Entered new entry to OpenVPN configs: us6739_nordvpn_udp
root: (./vpn-profile-switcher.sh) Currently active server: cy14_nordvpn_udp
root: (./vpn-profile-switcher.sh) Enabling new entry
root: (./vpn-profile-switcher.sh) Disabling current active server
root: (./vpn-profile-switcher.sh) Comitting changes and restarting OpenVPN
root: (./vpn-profile-switcher.sh) Removing unused NordVPN profiles, leaving current and last used.
Connect to a standard VPN server in Argentina over TCP
# ./vpn-profile-switcher.sh -c 10 -p tcp
Connect to a standard VPN server in Israel over UDP (default protocol)
# ./vpn-profile-switcher.sh -c israel
Connect to a recommended VPN server in North America (USA and Canada) over UDP (default protocol)
It is possible to use crontab for maintaining a connection to a recommended server. In this basic example, the script runs once an hour (at a round hour) to get the recommended server in the area the router is connected to, over UDP (default protocol).
0 */1 *** /root/vpn-profile-switcher.sh
The output will be displayed in the system log, like so:
Wed Jan 13 23:02:00 2021 cron.info crond[22011]: USER root pid 22868 cmd /root/vpn-profile-switcher.sh
Wed Jan 13 23:02:00 2021 user.notice root: (/root/vpn-profile-switcher.sh) Arguments: Protocol: udp; Country: ; NordVPN group: ; User credentials: secret.
Wed Jan 13 23:02:00 2021 user.notice root: (/root/vpn-profile-switcher.sh) Fetching VPN recommendations from: https://api.nordvpn.com/v1/servers/recommendations?filters[servers_technologies][identifier]=openvpn_udp&limit=1
Wed Jan 13 23:02:10 2021 user.notice root: (/root/vpn-profile-switcher.sh) Recommended server URL: il52.nordvpn.com.
Wed Jan 13 23:02:10 2021 user.notice root: (/root/vpn-profile-switcher.sh) Recommended server name: il52_nordvpn_udp
Wed Jan 13 23:02:10 2021 user.notice root: (/root/vpn-profile-switcher.sh) Currently active server: il38_nordvpn_udp
Wed Jan 13 23:02:10 2021 user.notice root: (/root/vpn-profile-switcher.sh) Enabling existing entry
Wed Jan 13 23:02:10 2021 user.notice root: (/root/vpn-profile-switcher.sh) Disabling current active server
Wed Jan 13 23:02:10 2021 user.notice root: (/root/vpn-profile-switcher.sh) Comitting changes and restarting OpenVPN
Using crontab, it is possible to set connection to different countries, groups, and over either UDP or TCP by scheduling running the script with different parameters. Check out both OpenWRT’s crontab documentation, and crontab guru for more details.
In any case, don’t forget to run /etc/init.d/cron restart to apply changes
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/UriShX/vpn-profile-switcher.
License
The script is available as open source under the terms of the MIT License.
Design for plastic injection molding: UAV fuel tank.
Design change in a flagship product, fueled by failure analysis. Lead engineer, salaried work for “Supergum”.
Mold and material change for high current aerial warning marker, after appearing to be part of a point failure. A comprehensive failure analysis, and mechanical testing of the new design lead to verified changes.
Stress and strain validation of a heat formed foot-rest concept. Design by Ziv Mishan, for his graduation project in product design at H.I.T.. Characterization of applied forces, appropriate model, and several iterations based on slight changes in geometry, based on client’s original design file. A report was produced to convey suggested changes in design.
Scientific article, published in “Polymer Composites”. Based on my plastics engineering graduation project at Shenkar College for engineering and Design.
Hand built acoustic guitar. Designed and built by me during my studies with Paul Doyle at The Irish School of Lutherie.
Top - Spruce. Back and Sides - Maple. Neck - London Plain.
A Liquid tag plugin for Jekyll that replaces the built in {% highlight %} tag, and allows passing the language to highlight in as a parameter.
An issue for making this change a part of the mainline Jekyll Highlight tag can be found here.
It appears v0.0.1 did not actually work as intended, and was simply failing gracefully by detecting the language from the code itself. A better job of detecting errors and alerting the user was devised in v0.0.2.
Then add the following to your site’s _config.yml:
plugins:-jekyll-highlight-param
💡 If you are using a Jekyll version less than 3.5.0, use the gems key instead of plugins.
Usage
Basic usage
Basic usage is the same as Jekyll’s {% highlight %} tag, i.e.:
{%highlight_paramruby%}
def foo
puts 'foo'
end
{%endhighlight_param%}
Using variables names for the language
Please note: Since v0.0.2 passing variables to the highlight_param tag is done in a similar way to the syntax for passing variables to other tags, such as link. This is a breaking change from v0.0.1.
The name of the language you for the code to be highlighted can be specified as a variable instead of specifying the language directly in the template. For example, suppose you defined a variable in your page’s front matter like this:
In this example, the capture will store the include file _includes/footer_company_a.html, then the highlight will would match the display to match the syntax of liquid.
Line numbers
You could also pass a line numbers argument, as in the original {% highlight %} tag, both as parameter and as a variable. Line numbers are enabled when passing the linenos argument, and disabled as default.
{%highlight_paramrubylinenos%}
def foo
puts 'foo'
end
{%endhighlight_param%}
or:
---title:My pageline_numbers:linenos---
{%highlight_paramruby{{page.line_numbers}}%}
def foo
puts 'foo'
end
{%endhighlight_param%}
Contributing
Fork it.
Create your feature branch (git checkout -b my-new-feature)
Commit your changes (git commit -am 'Add some feature')
Push to the branch (git push origin my-new-feature)