I build my first 3D Printer! The Creality Ender 3 may be a budget option without flashy features, but it doesn’t have to stay this way! I don’t want to babysit my 3D printer constantly, so for the last 3 weeks, I have been working on mobile notifications for 3D printers. It’s time to showcase what I have cooked up! It works with any Octoprint enabled printer.
Awesome mobile notifications for 3D printers
Neither Octoprint’s web interface, or existing solutions (Pushbullet, Telegram) were close to what I would like to have, so I decided to take the matter in my own hands. I’m pleased to say, that the project got even more features than I initially set!
Features:
support for 6 filament types (PLA, ABS, TPU, PETT, PETG, HIPS)
support for different spool sizes (just enter weight)
filament cost calculation (per print)
energy cost calculation (per print)
total cost of the print
supports 2 energy tariffs
Live view and snapshots in Android notifications
Print ETA time
Print Calculated time
Progress in % and progress bar
Support for multiple printers and phones
Print data export (name, printer, cost breakdown, time)
Commands (pause, resume, cancel)
Auto ON/OFF
180 degree time-lapse *
Custom lights*
Custom Enclosure *
*these are features I’m still working on
As you can see, this mobile notifications for 3D printers system has a pretty extensive list of features that can be added to ANY Octoprint enabled printer. There are a couple of things that you will need to read and learn first.
Requirements
To create your own mobile notifications for 3D printers you will need to get yourself familiar with the following reading list (skip links if you are familiar with the topic). You can simply just download ready made files, but before you ask questions – please check the articles.
I know the list is extensive already, but this is a very difficult tutorial to breakdown already. If you want to have something awesome, you will have to commit some time.
Limitations
I’m working with file events without indexing the names, so this only works with a single file uploaded to Octoprint. It’s not a big deal as you have to remove the print first to start a new one.
I gave you some options, pick your best prices. I listed the printer from banggood.com as they are my sponsor for the 3D Printing action so give them some love!
Let’s make mobile notifications for 3D printers
First of all, this is an overview. I’m not able to write a step by step guide to every single action. It meant to guide you through the process giving you enough info to get you started with the existing files. The NodeRED Flow should work off the box.
You will need a Raspberry Pi with a running Octoprint. I will leave the Octoprint config for you – there is plenty of tutorials there. Open settings and download the MQTT plugin. I’m using it to intercept the printer’s events. There is also API key to make the note of. You will need to feed this into the flow.
Look for MQTT plugin
I will assume you know how the Perfect Notifications work, you also completed the NodeRED for beginners.
Hardware
There was a reason I talked about Sonoff POW R2. I knew exactly where it is going to end up. I flashed it with Tasmota to get MQTT, spliced the 3D Printer’s cable and mounted the Sonoff using 3M tape. It will stay there.
I won’t be powering the Rasbperry Pi running the Octoprint from the printer’s power supply as I have other plans for that. It looks neat, I’m happy with that.
Buy Sonoff POWR2
Buy it using these links to support NotEnoughTech.
A lot of data is saved locally. All the settings or current print values are stored using the methodflow.set(). To preserve these, I enabled saving values. It’s crucial you do the same, just follow instructions in this post.
In the essense, each time I have a piece of data coming from the printer. I will save it as variable. These will get overridden with new prints, and I reference it a lot across my functions.
Settings
Configure the parameters
Mobile notifications for 3D Printers comes with config flow. These inject nodes (I may replace it with a custom Octoprint interface if I learn how) set up the environment for the print. You can preset:
filament type and diameter
filament size and cost
energy tariff time and cost
phone API for notifications
I was not sure where I can find the info about flament profile in Octoprint, otherwise I would link the selection of the filament with the data coming from the printer.
Either way, it’s easier to configure something like this, than go through each function node looking for the references. There is also a message that will let you know if something is not ready for calculations.
Enable/Disable flows
If you seen the video, you know that I have different notification for warm up, and another one for the actual print update. I needed a way to control when these would be showing up, even if Octoprint events were treating the warm-up period and printing as one.
I came up with a neat solution when I would use print progress change to disable the warm-up messages. I used that method of letting the payloads through a couple of times before and it works well. You will see a bunch of XXXX Enable nodes. These are there to control what shows up when and usually it’s activated from a relevant node.
Events – the heart of the flow
This is the brains of the operation
Octoprint can post a lot of data each time something happens at the server level. I used that to obtain most of the events and info about the print. The main events I monitor are:
FirmwareData(printer connected get details)
FileAdded(check if settings are set)
FileSelected(turn on the 3d printer, get print info)
FileRemoved (turn off the 3d printer)
PrintStarted (show preheat info and estimated cost)
Printing (update the notification every 30sec or 1%)
PrintPaused (display resume variant)
PrintResumed (display the standard variant)
PrintCancelled (cancel the print and clear variables, remove notifications)
PrintDone (calculate the power and total cost, display a new message)
These are available using MQTT topic: octoprint/event/. Each action has the corresponding behaviour in the NodeRED.
Pre-print information
This will loop until file details are available
When the Octoprint is connected (FirmwareData), the information about the printer is saved as flow variable.
A file can be loaded to the Octoprint. Mobile notifications for 3D Printers will check if all settings has been selected. The flow for file info will get enabled, otherwise an android notification is sent with the prompt to set up much needed details.
FUNCTION NODE: File added
var printer = flow.get("PrinterName");
var model = flow.get("PrinterModel");
var firmware = flow.get("PrinterFirmware");
var density = flow.get("filamentDensity");
var price = flow.get("filamentPriceG");
var filamentDiameter = flow.get("filamentDiameter");
if(printer === undefined || model === undefined || firmware === undefined || density === undefined || price === undefined || filamentDiameter === undefined){
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
var option1, option2, option3, option4 = " ";
if(printer === undefined || model === undefined || firmware === undefined){
option4 = " and reconnect the printer"
}
if(density === undefined){
option1 = " Filament type ";
}
if(price === undefined){
option2 = ", Filament price and weight ";
}
if(filamentDiameter === undefined){
option3 = ", Filament diameter ";
}
var title = "Print settings not configured";
var titleexpanded = "Please configure the follwing settings";
var text = "Set up the variable" + option1 + option2 + option3 + option4;
var textexpanded = "Set up the variable" + option1 + option2 + option3 + option4;
var body = {
"text": {
"text": text,
"textexpanded": textexpanded
},
"title": {
"title": title,
"titleexpanded": titleexpanded
},
"icons": {
"navbaricon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"bigicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"smallicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"iconexpanded": "https://image.flaticon.com/icons/png/512/44/44238.png"
},
"notificationid": "Ender3",
"persistent": false,
"cancel": false,
"priority": 3,
"color": "#b9512c",
"backgroundcolor": "#fafafa",
};
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
flow.set("dataPresent",false);
return [msg,null];
}
flow.set("dataPresent",true);
return [null, msg];
Once the file is selected, NodeRED will keep spamming the Octoprint every 2 seconds until it gets the details of the print. Make sure to add your API key from Octoprint. I saved it as a global variable using my credentials system.
Query Octoprint: function nodes
Query OctoprintPrint StatsSave Data
//check octoprint for API key - see credential tutorial http://notenoughtech.com/home-automation/nodered-home-automation/serving-credentials-with-nodered/
var APIKey = global.get("API_octoprint");
msg.url = "octoprint.local/api/job?apikey=" + APIKey;
return msg;
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
flow.set("pausePrePrintInfo", false);
var title = flow.get("PrinterModel") + " has a new file";
var titleexpanded = flow.get("PrinterName")+ " "+ flow.get("PrinterModel")+ " has loaded new file.";
var text = "The print ETA is "+ flow.get("PrintTime");
var textexpanded = "The print ETA is "+ flow.get("PrintTime")+ ", and will use "+flow.get("PrintFilament")+" of filament.";
var body = {
"text": {
"text": text,
"textexpanded": textexpanded
},
"title": {
"title": title,
"titleexpanded": titleexpanded
},
"icons": {
"navbaricon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"bigicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"smallicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"iconexpanded": "https://image.flaticon.com/icons/png/512/44/44238.png"
},
"notificationid": "Ender3",
"persistent": true,
"cancel": false,
"priority": 2,
"color": "#b9512c",
"backgroundcolor": "#fafafa",
"buttons": [
{
"button1": {
"icon": "iconURL",
"label": "LiveView",
"command": "=Ender3=liveview"
},
"button2": {
"icon": "iconURL",
"label": "STOP",
"command": "=Ender3=stop"
}
}
]
};
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
return msg;
//calculate print time
function timeConvert(duration) {
var seconds = parseInt(duration % 60);
var minutes = parseInt((duration / 60) % 60);
var hours = parseInt((duration / 3600) % 24);
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + "h:" + minutes + "m:" + seconds + "s";
}
//calculate filament in meters
function filamentConvert(lenght){
var x = Math.floor(lenght);
var m = parseInt(x / 1000);
var cm = parseInt(x % 100);
return m + "m:" + cm +"cm";
}
//ETA time
if(msg.payload.job.estimatedPrintTime === null){
var printtime = "not available";
}
if(msg.payload.job.estimatedPrintTime !== null){
var printtime1 = Math.floor(msg.payload.job.estimatedPrintTime);
var printtime = timeConvert(printtime1);
}
//Calculated time
if(msg.payload.progress.printTimeLeft === null){
var printtimeleft = "not available";
}
if(msg.payload.progress.printTimeLeft !== null){
var printtimeleft1 = Math.floor(msg.payload.progress.printTimeLeft);
var printtimeleft = timeConvert(printtimeleft1);
}
//Filament
if(msg.payload.job.filament === null){
var filamentused = "not available";
}
if(msg.payload.job.filament !== null){
var filamentused1 = Math.floor(msg.payload.job.filament.tool0.length);
//flow.set("filamentInmm",filamentused1);
var filamentused = filamentConvert(filamentused1);
}
// set flow variables
flow.set("PrintTime",printtime);
flow.set("PrintETA",printtimeleft);
flow.set("PrintFilament",filamentused);
//debug
msg.payload = {
"printtime":printtime,
"printtimeleft": printtimeleft,
"filamentused": filamentused
}
return msg;
The details from these tasks are saved as variables and the NodeRED is ready to get the printing command. This loop is not accessible unless all variables are set in the settings menu.
Print - pre heat phase
Getting temps
To print, the extruder and bed have to reach certain temperatures. The temps are available in the bed: octoprint/temperature/bed and an extruder: octoprint/temperature/tool0 topics. This flow is activated in the preheat flow triggered by PrintStarted event. At the same time, the printer is turned on by Sonoff POW R2.
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
flow.set("pausePrePrintInfo",true);
var density = flow.get("filamentDensity");
var length = flow.get("filamentInmm");
var price = flow.get("filamentPriceG");
var filamentDiameter = flow.get("filamentDiameter");
var currency = "£";
var cost1 = ((3.14 * (Math.pow((filamentDiameter/2),2)) * length/10)* density) * price;
var cost2 = Math.round(cost1 * 100) / 100;
var cost = currency + cost2;
flow.set("CostOfFilament", cost2);
var title = flow.get("PrinterModel") + " is getting ready to print!";
var titleexpanded = "New file has been loaded to "+ flow.get("PrinterModel") + ". The printer is warming up!";
var text = "ETA print time "+ flow.get("PrintTime")+ "Filament needed "+flow.get("PrintFilament");
//var textexpanded = "The print ETA is "+ flow.get("PrintTime")+ ", and will use "+flow.get("PrintFilament")+" of filament. This operation will cost you " + cost;
var textexpanded = "
The print ETA: "+flow.get("PrintTime")+
"
Filament used: "+flow.get("PrintFilament")+
"
Cost: "+cost+
"
Bed Temp: "+flow.get("TempBed")+
" ºC
Extruder Temp: "+flow.get("TempExtruder")+
" ºC
";
var body = {
"text": {
"text": text,
"textexpanded": textexpanded
},
"title": {
"title": title,
"titleexpanded": titleexpanded
},
"icons": {
"navbaricon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"bigicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"smallicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"iconexpanded": "https://image.flaticon.com/icons/png/512/44/44238.png"
},
"notificationid": "Ender3",
"persistent": false,
"cancel": false,
"priority": 0,
"cost": cost,
"color": "#b9512c",
"backgroundcolor": "#fafafa",
"buttons": [
{
"button1": {
"icon": "iconURL",
"label": "Cancel",
"command": "=Ender3=stop"
}
}
]
};
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
return msg;
This will continue updating the notification every 30 sec until the printing is in progress.
Turn Printer on/off and enable printer
Since the printer is now powered on, we should start monitoring the power use. This is why you see the Printer data on/off (power data) toggles. It actually took me several hours to figure out the best approach if you want to have more than a single tariff.
Printing in progress
Calculating the use of power using multiple tariffs had proven to be complicated at first. Instead of creating the time ranges, I decided to use an alternative solution. In reality, I probably run my prints crossing 2 different power rates. To to calculate this efficient as possible, I will calculate how much I pay per minute (at current rates) and then sum up the cost in total. This will save me calculating the power use in tariff 1 vs tariff 2 and the tariff N.
FUNCTION NODE: Calculate power
var power = msg.payload.StatusSNS.ENERGY.Power;
var price = flow.get("ElectricityCost");
var total = flow.get("CostOfPower");
//check if array exists
if(!total || !total.length){
total = [];
}
var costPerMinute = power/1000 * price / 60;
total.push(costPerMinute);
flow.set("CostOfPower", total);
//debug
msg.costPerMinute = total;
return msg;
The calculation will continue until the end of the printing process. I will add the values from the total[] array when the final notification is being created.
Print is happening
Extruder is hot, so is the print bed. The print is being created layer by layer. At this point I would like to get a new notification. I will cancel the warm-up message flow and start the print updates.
These will be pushed to the phone every 30 sec or 1% whichever is slower. If you open your ports, you will be able to receive the pictures from Octoprint and use it in your Android notification.
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
flow.set("pausePrePrintInfo", false);
var streamURL = global.get("octoURL") + ":8080/?action=snapshot";
var title = "Printing progress: "+ flow.get("PrintProgress")+"%. on" +flow.get("PrinterModel");
var titleexpanded = "Printing progress: "+ flow.get("PrintProgress")+"%. on" +flow.get("PrinterModel");
var text = "ETA "+ flow.get("PrintETA");
var textexpanded = "ETA: "+flow.get("PrintTime")+
". Time left: "+flow.get("PrintETA");
var progress = flow.get("PrintProgress");
var body = {
"text": {
"text": text,
"textexpanded": textexpanded
},
"title": {
"title": title,
"titleexpanded": titleexpanded
},
"icons": {
"navbaricon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"bigicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"smallicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"iconexpanded": "https://image.flaticon.com/icons/png/512/44/44238.png"
},
"notificationid": "Ender3",
"persistent": true,
"cancel": false,
"priority": 0,
"progress": progress,
"maxprogress": 100,
"color": "#b9512c",
"backgroundcolor": "#fafafa",
"picture": streamURL,
"url": streamURL,
"buttons": [
{
"button1": {
"icon": "iconURL",
"label": "LiveView",
"command": "=Ender3=liveview"
},
"button2": {
"icon": "iconURL",
"label": "Pause",
"command": "=Ender3=pause"
},
"button3": {
"icon": "iconURL",
"label": "STOP",
"command": "=Ender3=stop"
}
}
]
};
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
return msg;
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
var title = "Printing on "+flow.get("PrinterModel")+ " is PAUSED";
var titleexpanded = flow.get("PrinterName")+ " "+ flow.get("PrinterModel")+ "is PAUSED.";
var text = "ETA "+ flow.get("PrintETA");
var textexpanded = "
The print ETA: "+flow.get("PrintTime")+
" Time left: "+flow.get("PrintETA")+
" Progress: "+flow.get("PrintProgress")+
"% Bed Temp: "+flow.get("TempBed")+
" ºC Extruder Temp: "+flow.get("TempExtruder")+
" ºC
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
flow.set("printUpdate", false);
flow.set("PrintProgress",0);
flow.set("CostOfPrint", null);
flow.set("CostOfPower", null);
flow.set("CostOfFilament", null);
flow.set("pausePrePrintInfo", false);
var title = flow.get("PrinterModel");
var titleexpanded = "The printing job on "+flow.get("PrinterModel")+ " has been cancelled";
var text = "The print has been cancelled";
var textexpanded = "The print has been cancelled";
var body = {
"text": {
"text": text,
"textexpanded": textexpanded
},
"title": {
"title": title,
"titleexpanded": titleexpanded
},
"icons": {
"navbaricon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"bigicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"smallicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"iconexpanded": "https://image.flaticon.com/icons/png/512/44/44238.png"
},
"notificationid": "Ender3a",
"persistent": false,
"cancel": false,
"priority": 3,
"color": "#b9512c",
"backgroundcolor": "#fafafa"
};
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
return msg;
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
flow.set("printUpdate", false);
flow.set("PrintProgress", 0);
var body = {
"notificationid": "Ender3",
"cancel": true
};
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
return msg;
//calculate print time
function timeConvert(duration) {
var seconds = parseInt(duration % 60);
var minutes = parseInt((duration / 60) % 60);
var hours = parseInt((duration / 3600) % 24);
hours = (hours < 10) ? "0" + hours : hours;
minutes = (minutes < 10) ? "0" + minutes : minutes;
seconds = (seconds < 10) ? "0" + seconds : seconds;
return hours + "h:" + minutes + "m:" + seconds + "s";
}
//message
var key = flow.get('CurrentPhone');
var url = "https://autoremotejoaomgcd.appspot.com/sendmessage";
var command = "NOT20";
var totaltime = timeConvert(msg.payload.time);
var filename = msg.payload.filename;
flow.set("FileName", filename);
flow.set("FinishedPrintTime", totaltime);
//cost calculation
var sum = flow.get("CostOfPower");
function add(accumulator, a) {
return accumulator + a;
}
var costOfElectricity = sum.reduce(add);
var costOfFilament = flow.get("CostOfFilament");
if(costOfElectricity <0.01){
costOfElectricity = 0.01;
}
var costOfPrint = Math.round(costOfElectricity * 100) / 100 + costOfFilament;
//clear cost valuses and store total cost
flow.set("CostOfPrint", costOfPrint);
flow.set("CostOfPower", null);
flow.set("CostOfFilament", null);
// format messages
var title = flow.get("PrinterModel") + " the print job is finished.";
var titleexpanded = flow.get("PrinterModel")+ " has completed the job.";
var text = flow.get("PrinterModel")+ " has finished printing" + ". The total cost is " +costOfPrint;
var textexpanded = "The print is ready. Please collect it from "+ flow.get("PrinterModel")+
". The print cost breakdown is: Electricity £"+costOfElectricity + " + Filament £"+ costOfFilament + " = £" +costOfPrint;
// AR Body
var body = {
"text": {
"text": text,
"textexpanded": textexpanded
},
"title": {
"title": title,
"titleexpanded": titleexpanded
},
"icons": {
"navbaricon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"bigicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"smallicon": "https://image.flaticon.com/icons/png/512/44/44238.png",
"iconexpanded": "https://image.flaticon.com/icons/png/512/44/44238.png"
},
"notificationid": "Ender3a",
"persistent": false,
"cancel": false,
"priority": 3,
"printStats": filename+"|"+totaltime+ "|"+costOfPrint+"|"+ Math.round(costOfElectricity * 100) / 100 +"|"+ costOfFilament,
"color": "#b9512c",
"backgroundcolor": "#fafafa",
"buttons": [
{
"button1": {
"icon": "iconURL",
"label": "PICTURE",
"command": "=Ender3=liveview"
},
"button2": {
"icon": "iconURL",
"label": "Download timelapse",
"command": "=Ender3=downloadTL"
},
"button3": {
"icon": "iconURL",
"label": "Save Print Stats",
"command": "=Ender3=export"
},
}
]
};
//send Perfect Notification 2.0
var x = JSON.stringify(body);
var encodedBody = encodeURIComponent(x);
msg.url = url + "?key=" + key + "&message=" +command + "=:="+ encodedBody;
return msg;
Android Notifications
For the most part, I'm following the Perfect Notifications write up. There are small changes regardless of the messages displayed by Tasker. The differences are caused by the fields being populated by variables, but not being in use.
In AutoNotification, if you add the "progress bar" variable and set it to "null" the progress bar will still display as empty. This is why I have several versions of the same notification. I also use the most important variable in Tasker way of passing the information - it's a great way of dealing with Tasker sensitive data.
TASKER PROFILE: Perfect AutoNotification AR
Profile: Perfect AutoNotification AR
Event: AutoRemote [ Configuration:NOT20 ]
Enter: PN Create Notification
A1: Variable Set [ Name:%Test To:%arcomm Recurse Variables:Off Do Maths:Off Append:Off ] If [ %arcomm Set ]
A2: Variable Set [ Name:%Test To:%aacomm Recurse Variables:Off Do Maths:Off Append:Off ] If [ %aacomm Set ]
A3: AutoTools Json Read [ Configuration:Input Format: Json
Json: %Test
Fields: text.text,text.textexpanded,title.title,title.titleexpanded,icons.navbaricon,icons.bigicon,icons.iconexpanded,buttons[0].button1.label,buttons[0].button1.icon,buttons[0].button1.command,buttons[0].button2.label,buttons[0].button2.icon,buttons[0].button2.command,
buttons[0].button3.label,buttons[0].button3.icon,buttons[0].button3.command,priority,persistent,notificationid,progress,maxprogress,picture,url,cancel,printStats
Separator: , Timeout (Seconds):60 ]
A4: AutoNotification [ Configuration:Title: %title_title
Text: %text_text
Url: l
Icon: %icons_bigicon
Status Bar Icon Manual: %icons_navbaricon
Status Bar Text Size: 16
Background Color: %color
Colorize Background: true
Id: %notificationid
Priority: %priority
Persistent: %persistent
Title Expanded: %title_titleexpanded
Text Expanded: %text_textexpanded
Icon Expanded: %icons.iconexpanded
Separator: ,
Button 1: %buttons_button1_command
Label 1: %buttons_button1_label
Action Icon 1 Manual: %buttons_button1_icon
Button 2: %buttons_button2_command
Label 2: %buttons_button2_label
Action Icon 2 Manual: %buttons_button2_icon
Button 3: %buttons_button3_command
Label 3: %buttons_button3_label
Action Icon 3 Manual: %buttons_button3_icon Timeout (Seconds):20 ] If [ %cancel ~ false & %maxprogress !Set ]
A5: AutoNotification [ Configuration:Title: %title_title
Text: %text_text
Url: %url
Icon: %icons_bigicon
Status Bar Icon Manual: %icons_navbaricon
Status Bar Text Size: 16
Background Color: %color
Colorize Background: true
Id: %notificationid
Priority: %priority
Max Progress: 100
Progress: %progress
Persistent: %persistent
Title Expanded: %title_titleexpanded
Picture: %picture
Skip Picture Cache: true
Text Expanded: %text_textexpanded
Icon Expanded: %icons.iconexpanded
Separator: ,
Button 1: %buttons_button1_command
Label 1: %buttons_button1_label
Action Icon 1 Manual: %buttons_button1_icon
Button 2: %buttons_button2_command
Label 2: %buttons_button2_label
Action Icon 2 Manual: %buttons_button2_icon
Button 3: %buttons_button3_command
Label 3: %buttons_button3_label
Action Icon 3 Manual: %buttons_button3_icon Timeout (Seconds):20 ] If [ %cancel ~ false & %maxprogress Set ]
A6: AutoNotification Cancel [ Configuration:Id: %notificationid
Cancel Persistent: true Timeout (Seconds):20 ] If [ %cancel ~ true ]
A7: Variable Set [ Name:%LastPrint To:%printstats Recurse Variables:Off Do Maths:Off Append:Off ] If [ %printstats Set ]
I will need 2 notification types. One with the print update (progress bar) and the template for other notifications. In addition to this I have added the AutoNotification Cancel, to be able to remove the persistent settings.
Lastly I have added an option to gather information about the last completed print. It's a variable that is pushed to an array when the print has been completed.
AutoNotification commands
I also made a list of custom commands. All respond to the =Ender3= prefix and each action has a differen IF condition. For Pause/Resume/Cancel these are simple HTTP requests sent back to NodeRED.
TASKER PROFILE: Ender 3 Commands
Profile: Ender3 Commands
Event: AutoNotification [ Configuration:Event Behaviour
Filter: =Ender3=* (regex) ]
Enter: Ender3 Commands
A1: HTTP Post [ Server:Port:%HTTPrequest Path:/Ender Data / File:printer=Pause Cookies: User Agent: Timeout:10 Content Type: Output File: Trust Any Certificate:On ] If [ %anmessage ~R pause ]
A2: HTTP Post [ Server:Port:%HTTPrequest Path:/Ender Data / File:printer=Resume Cookies: User Agent: Timeout:10 Content Type: Output File: Trust Any Certificate:On ] If [ %anmessage ~R resume ]
A3: HTTP Post [ Server:Port:%HTTPrequest Path:/Ender Data / File:printer=Cancel Cookies: User Agent: Timeout:10 Content Type: Output File: Trust Any Certificate:On ] If [ %anmessage ~R stop ]
A4: AutoTools Chrome Custom Tabs [ Configuration:Url: http://hometime.ddns.net/webcam/?action=stream Timeout (Seconds):300 ] If [ %anmessage ~R liveview ]
A5: Array Push [ Variable Array:%PrintedItems Position:1 Value:%LastPrint Fill Spaces:Off ] If [ %anmessage ~R export ]
To see the LiveView I used a custom Chrome window with a defined URL. (you can get the URL in the Octoprint setting - forward port 8080 to have access to the camera on the go). Lastly, to save the print details to an array (feel free to use that data in whatever way you wish) I used Push to Array action.
Over all the Tasker part of this relies on the Perfect Notification tutorial. I have added extra JSON fields when I felt it's needed, but that's pretty much all. It show how good that Tasker project is and how flexible are these notifications.
Conclusion
This has been one of the more challenging projects I took on. I learned new things, I feel more comfortable with JavaScript and I'm looking forward to countless hours I spend with my 3D printer. I still have some work to do, so I will continue bug hunting, and working on the 180-degree camera jig and some extra LED lights. So if you are interested - follow me for updates. If you enjoy mobile notifications - consider buying me a coffee... I spent most of my budget on that boost! Questions? Hit the Reddit post here.
Project Download
Download project files here. Bear in mind that Patreon supporters have early access to project files and videos.
I have upgraded from the cheapest soldering stand you could get, to the second soldering stand. Now, let's make this DANIU Soldering stand a tiny bit better with a little bit of printing.
This website uses cookies so that we can provide you with the best user experience possible. Cookie information is stored in your browser and performs functions such as recognising you when you return to our website and helping our team to understand which sections of the website you find most interesting and useful.
Strictly Necessary Cookies
Strictly Necessary Cookie should be enabled at all times so that we can save your preferences for cookie settings.
If you disable this cookie, we will not be able to save your preferences. This means that every time you visit this website you will need to enable or disable cookies again.