notifications upon start/pause/finish of print
-
@Torin Thanks for the quick update!
I documented a little of my setup to help with troubleshooting, maybe something has changed on Slack's end?
Here is my webhook setup:
And here is the next action in the workflow:
This is the result posted to the channel:
Is there a way to post to a channel from a webhook w/o using the workflow tool? Maybe that's something I missed....
-
Actually just tested it quickly. It works literally as you did. Just copy paste slack webhook url, put it in config and it should just appear.
text is not needed, as it is send via attachments in slack:
https://api.slack.com/reference/messaging/attachments -
@Torin Well it works perfectly when set up properly
So to change the content of the attachment, I just need to update these sections and recompile?
func sendNotification(status rrStatusType, fileinfo rrFileinfoType) { messageTitle := `Your friendly 3d printer status` messageText := fmt.Sprintf(`Status: %v, print file name: %v, print time: %v`, returnStatus(status.Status), fileinfo.FileName, niceTime(fileinfo.PrintDuration)) if status.TimesLeft.File != 0 && status.Status == `P` { messageText = fmt.Sprintf(`, print time left: %v`, niceTime(int(status.TimesLeft.File))) }
and
if viper.GetBool(`notifications.slack.enabled`) && viper.Get(`notifications.slack.webhookurl`) != `` && contains(returnStatus(status.Status), viper.GetStringSlice(`notifications.slack.when`)) { go func(messageText string, messageTitle string) { log.Printf("Sending slack message\n") message := slackRequestBody{ Attachments: []attachment{{ Title: messageTitle, Text: messageText, Color: "good", }, }, } sendSlackNotification(message) }(messageTitle, messageText) }
Thank you for putting this together!
-
@Torin said in notifications upon start/pause/finish of print:
Also added re-notify feature.
The re-notify feature does not appear to be working under windows. I receive the first notification for any new status, but no subsequent updates after status changes. I see a reference to time.Now().Unix() in the main.go source, could this be part of the issue?
-
@mct82 Basically yeah, you would also need to update struct for json payload.
In regards to windows, time.Now().Unix() should without any problem on windows. That's something I would need to check later during the week. but feel free to look around, add some timers maybe and logging -
@Torin I'm not a programmer and I have never used the Go language, so I don't think you want me mucking up your code. I just don't have time to learn a new language right now, so I will have to wait for someone who knows what they're doing to do it properly.
I will mention that if I were to modify this tool in any way, it would be to pull the message content out so it can be edited w/o re-compiling. Perhaps read in a message template for each status (print, pause, finish), or a single template with multiple sections. It would be really powerful to be able to grab additional fields from the OM to include in (or conditionally modify) push notifications.
-
@mct82 Hey, so I got a bit of spare time today and I've looked into it. Renotifications didn't work because I forgot to add two more if's.
I've created new release here: https://gitlab.com/Toriniasty/reprap_notify/-/releases/v7
-
Hi, this is working great for me, but is there a way to make it poll for 2 duet boards? I have two printers I would like to use it on.
-
This is fantastic. Just what I was looking for.
I tried running this on windows from command line, but theres no feedback... so im not even sure its running?
I do have a spare raspberry pi lying around so which release would I use for that?
-
@thebaseddoge Simply start two programs with from two different directories with two different config files
@festivejelly There's no feedback unless there's a problem If you want to run on rpi you need an arm build.
-
@torin So do I run from command line? or do I just double click the exe? When I do either I dont see the process running in the list. Ill give the arm build a try instead on my rpi
-
@festivejelly You can run it both ways, either from command line or double click. If it doesn't quit and windows stay open it should just work.
-
@torin I don't know if you planned on maintaining this app, but it sure would be nice if it received an update.
I did some testing and got a contineous stream of JSON parse errors. After checking the sources it seems the program uses the GET /rr_status way of talking to the Duet. However, according to this page on the Duet Github, it is deprecated now.Should you decide to maintain it, I could make time to help out testing.
-Nxt
-
-
@madeinta1wan This is due to API changes introduces in RRv3. There's a chance but it requires few hours of work which I currently do not have, however I will try to squeeze that in somehow. The code is opensource so if someone would make an PR I will happily merge it.
-
@madeinta1wan @madeinta1wan rr_status is still supported in standalone mode AFAIK. We will add a support layer for rr_ requests to SBC mode in v3.5 but I'm afraid it won't support rr_status. If possible, I'd strongly recommend upgrading to rr_model which returns portions of the object model.
-
So I finally found some time and resurfaced my duet enabled printer so I have started updating the app.... So hopefully soon there will be something to show
@chrishamm How do I currently identify finished print? Previously it was in rr_status marked as 'I'(capital I), now I can see see only in rr_model?key=state status: idle, pause, printing.
-
@torin Those letters are abbreviations for the different machine states (see here), so
idle
is equal toI
. -
@chrishamm Many thanks for that, it definitely extends what I've seen.
However I am missing a 'final status' if that makes sense e.g. there's the status for cancelling yet there's no cancelled status or processing and no processed which makes it hard to understand and put the proper function in place to determine final status without hammering the API and making a request every let say 100ms which could still lead to some false positives. -
This may help. Its some of the logic in DuetLapse3. It ends up being a bit convoluted .... and of course I have a bunch of defensive coding in here (for other reasons).
The main logic starts at line 16.Any yes - it can do with a bit of tidying up
def captureLoop(): # Run as a thread global printState, duetStatus, captureLoopState if connectionState is False: return captureLoopState = 1 printState = 'Not Capturing' lastDuetStatus = 'idle' # logical state on start of each thread instance logger.debug('Starting Capture Loop') while captureLoopState == 1: # Set to 0 to stop. e.g By http listener or SIGINT or CTL+C if duetStatus != lastDuetStatus: # What to do next? logger.info('****** Duet status changed to: ' + str(duetStatus) + ' *****') # logical states for printer are printing, completed if duetStatus == 'idle' and printState in ['Capturing', 'Busy'] and terminateState != 1: # Capturing is finished without being commanded printState = 'Completed' logger.debug('****** Print State changed to ' + printState + ' *****') elif duetStatus in ['processing', 'idle'] or (duetStatus == 'paused' and detect == 'pause'): printState = 'Capturing' logger.debug('****** Print State changed to: ' + printState + ' *****') elif duetStatus == 'busy': printState = 'Busy' logger.debug('****** Print State changed to: ' + printState + ' *****') else: printState = 'Waiting' logger.info('****** Print State changed to: ' + printState + ' *****') if printState == 'Capturing': oneInterval('Camera1', camera1, weburl1, camparam1) if camera2 != '': oneInterval('Camera2', camera2, weburl2, camparam2) unPause() # Nothing should be paused at this point elif printState == 'Completed': logger.info('Print Job Completed') printState = 'Not Capturing' # use a thread here as it will allow this thread to close. startnextAction('completed') break # Do not want to wait to end if captureLoopState == 1 and terminateState != 1 and connectionState: # If still running then sleep lastDuetStatus = duetStatus time.sleep(poll) printState = 'Not Capturing' captureLoopState = -1 return # End of captureLoop