Closed geffaelden closed 1 year ago
I have no way of testing this (I don't have that printer) but I expect it to work pretty much the same way, except with a larger image. The mini link uses a 600x800 image so I think the square would use 800x800?
Though I can also imagine the code being slightly different as the same filesize limit but a larger image would mean a lower quality image will be printed.
If you have an Android phone you could try to record the bluetooth interaction and we can see what happens. See this post for info on doing that: https://github.com/jpwsutton/instax_api/issues/21#issuecomment-751651250
@geffaelden If you're on IOS and have a Mac you can also use their PacketLogger tool to record the data between your phone and the printer. Using those logs I should be able to see if / what needs to be changed in to code to support the SQUARE link.
I did this the other day and it's pretty straightforward. Basically the steps are:
Pretty clear steps can be found here: https://www.bluetooth.com/blog/a-new-way-to-debug-iosbluetooth-applications/
@javl I've done this but can't seem to figure out which log is for the image printing
@geffaelden On what platform? If you used Packet Logger with IOS you can just start recording, do the printing and stop recording, and send that complete file. There might be some other stuff in there but that doesn't matter, I can filter out the printer part.
@javl I used the iOS PacketLogger method. Here's the log of the test print I did: https://drive.google.com/file/d/1OZD5cZ8FS1ZkrVpG3Rx0y92isoHqskKw/view?usp=share_link
@geffaelden Thanks, I'll take a look as soon as I can 👍
@geffaelden Took a very quick look and it seems it shouldn't be too hard to adapt my code to work, just need to find the time ;) Thanks for the file! You can take it offline if you want, I've got a local copy.
@geffaelden Something is different compared to the way the Mini Link prints its images. Managed to get a 800x800 px image from your logs, but there are some glitches. Do you still have the image file you used for printing? If so I could compare it against what I get from to logs to see what is happening (the app sends over the actual image, so by comparing the original bytes with the logs I should be able to see what's changed).
Heres the test image I printed
Ok, that might explain something: the other printer only supports .jpg but this is .png (though the header in the logs seems to suggest jpg).
Thanks for the file.
It seems the square (and probably wide) apps allow you to select more image types (jpg, png and some newer formats used on IOS and Android) than the app for the Mini Link does (jpg only) but the app just converts the image to jpg before sending it to the printer. There was some error in my parser but now I'm able to extract your image from the logs, meaning I should be able to adapt my code to send your image to the printer as well. Stay tuned ;)
Not sure what would be the best approach: having the user set a device type (something like instax.set_model(square)
or detect the model based on the image (600x800 is mini link, 800x800 is square, and the wide probably uses 800x600?)
@geffaelden I think the fix to support the square is simple: can you try replacing chunkSize = 900
with chunkSize = 1808
and try printing again?
I successfully printed an image on the Instax Square Link 🥳 Using a chunkSize of 1808 did the trick! Initially, I encountered an issue with the incorrect image size, which was caused by faulty compression (see image 🤦🏼♂️). However, using an 800x800 JPEG resolved the problem. I developed my own implementation in TypeScript, utilizing the Bluetooth Web API, and drew significant inspiration from your work, @javl. Thank you for your great work!
In addition to this, I've been working on parsing other messages of the INSTAX Protocol, such as battery status, charging status, printed images, and more. I wanted to created an alternative UI to print images with an Instax printer via a web browser. I plan to upload my code to GitHub in the coming days.
@linssenste Wow, super cool! For my current project printing from Python is more useful, but being able to print straight from the browser is such a great idea! And way more accessible for people who don't know how to use Python! This is why I like to make my code open source!
Do post a link when your code is online, I'll add it to my readme.
@linssenste
By the way, I already have some of those features in some old code:
Send a message with opcode EventType.XYZ_AXIS_INFO
, InfoType.BATTERY_INFO
or InfoType.PRINTER_FUNCTION_INFO
and you can parse the results like this:
header, length, op1, op2 = unpack_from('>HHBB', response)
if (op1, op2) == EventType.XYZ_AXIS_INFO.value:
x, y, z, o = unpack_from('<hhhB', response[6:-1])
print(f'x: {x}, y: {y}, z: {z}, o: {o}')
return
elif (op1, op2) == EventType.SUPPORT_FUNCTION_INFO.value:
infoType = InfoType(response[6])
if infoType == InfoType.BATTERY_INFO:
self.batteryState, self.batteryPercentage = unpack_from('>BB', response[8:10])
print(f'battery state: {self.batteryState}, battery percentage: {self.batteryPercentage}')
return
elif infoType == InfoType.PRINTER_FUNCTION_INFO:
dataByte = response[8]
self.photosLeft = dataByte & 15
self.isCharging = (1 << 7) & dataByte >= 1
print(f'photos left: {self.photosLeft}, is charging: {self.isCharging}')
return
@javl Thanks!
I uploaded my source code in the repository and the project is accessible here: https://instax-link-web.vercel.app/
It’s currently only working with the SQUARE printer, but I have access to the mini and wide soon and will test and implement them. 🙃
I will work with your repository as well soon, as I want to programmatically control the printers as well, so we may also close this issue then.
Btw: if you want to scale images to test with the python code, you can just download the image, it’s already compressed and resized
For the mini just use a size of 900 as in my current code.
So we know: Mini 600x800, 900 bytes Square 800x800, 1808 bytes
I thought the wide was just the mini but on landscape, but looking at them online they look more like even larger versions of the square at 800 × 1260. So, 1808 bytes but more packets?
@linssenste Great readme by the way (and I love Jasper the dog)
@linssenste was thinking about adding a setting to specify the printer you're using, but then I read this in your readme
Once you connect your printer via Bluetooth, the app fetches specific details like battery status,
charging state, remaining prints, and allowed image dimensions (width and height). These
updates roll in every 2.5 seconds.
I totally forgot you can just get the model type from the printer :) Way more user friendly. But could you point me towards where you get the print size from the device? All the sizes I see in your repo seem to be hard-coded?
@javl yes, you are right. the adaption to the mini shall be pretty straight forward now :) I will add this functionality, and you may test it (you can abort before printing). I had a quick look at the wide-link protocol and there seems to be a variation how the chunks send, it seems to also have a chunk size of 900 but is using a different splitting of the chunks, but I have to look into that in more detail. I will share a record here as well :)
Yes, you can actually also get the type from the serial number (I guess square starts with 50, wide 20, mini ???) and there seems to be a readable printer type value in the DEVICE_INFO_SERVICE. But I worked with the image size, because I thought this was more convenient. It's actually not hardcoded - initially it is set to 800x800 and can be switched on the frontend. Once a printer is connected it the image size is read in the PrinterSettings.vue
fetch interval, basically the size is provided in the SUPPORT_FUNCTION_INFO 0
as two two byte integers. I tested it with the wide and the square and both are providing the correct size. You can test it with your mini and connect it to the App - it will automatically lock the image size to 600x800 :)
That works perfectly. You can also get the printer type from a code it sends: the Link Mini seems to be SP-4
, but I guess you don't really need anything beside the size it allows.
For the mini just use a size of 900 as in my current code.
So we know: Mini 600x800, 900 bytes Square 800x800, 1808 bytes
I thought the wide was just the mini but on landscape, but looking at them online they look more like even larger versions of the square at 800 × 1260. So, 1808 bytes but more packets?
Hi @javl, @linssenste,
Trying to make this work with a raspberry pi and an instax square link, so it's been a bit painful. Right now, my main problem is during the data packing when it creates packets for printing, with an 800x800 image and a chunksize of 1808.
self.packetsForPrinting = [ self.create_packet(EventType.PRINT_IMAGE_DOWNLOAD_START, b'\x02\x00\x00\x00\x00\x00' + pack('>H', len(imgData))) ]
I get an error:
Error: 'H' format requires 0 <= number <= 65535
The length of imagedata at that point is 90110, so more than the H format.
@vertgo
Your error is 'Error: 'H' format requires 0 <= number <= 65535' which seems to be correct if the length of your data is 90110, which is more than the max allowed 65535 from the error.
This suggests your image is about 90kb, try saving it at a lower quality so you end up around or below 65kb.
I've had trouble getting this to work with the Rpi so very curious to see your results. In my case it became VERY slow and I was thinking of moving back to a script that uses a bluetooth socket instead when running on a pi. Would love to get this working reliably.
@vertgo I was about to do some more tests on a pi. I think I mixed up some settings before: originally I used a socket with a packet size of 900, as used by the android app. Sockets didn't work on mac/windows so I moved to simplepyble but I kept the size at 900. Maybe it will run fine on the pi at 1808. The main problem was the speed, took about a minute to send one image, but at 1808 it might be way faster.
@javl I thought I posted last night, I got it working using 'i' instead of 'H'. It was a bit unreliable so there will have to be more tests. Would 'i' also work for the mini printer (I only have the square and the wide, about to try the wide). I could query the model and then decide which to use (square, mini or wide).
I tested it from mac and then got it working on the pi. Doing it from pi was a bit spotty, as the simplepyble required installing from piwheels and was only compatible with raspbian bullseye. It is slow, and speed is important to me, so if sockets are faster would love to try that.
self.packetsForPrinting = [
self.create_packet(EventType.PRINT_IMAGE_DOWNLOAD_START, b'\x02\x00\x00\x00\x00\x00' + pack('>i', len(imgData)))
]
@vertgo
The H
is an unsigned short of 2 bytes, while i
is a 4-byte integer, so I can imagine this will give trouble at some point as it offsets the content of your packet by 2 bytes, which the code on the printer doesn't expect.
The phone app will change the quality of the image to fit the size allowed, which I admit is not a lot: even for the 600x800 of the Link Mini 65kb is pretty low res. I think I'll add an option to do this automatically to the Python script later on (which basically just saves your image with lower and lower quality over and over until it finds a quality setting that gets the image below 65kb).
If you run your Pi with a desktop you could give the site @linssenste made a try (you need to enable bluetooth in your browser's settings). It already includes the resizing. https://instax-link-web.vercel.app/
I'd love to be able to use a single bluetooth backend for all systems, but if we can't find a way to speed up the transfer, adding another layer for the socket is needed I guess, as the Pi is also my main target device. I guess we could come up with some structure that allows the user to write a single script and let the module decide what backend to use automatically.
I never made a proper tag or branch with the old version, but if you want to give it a go I think the socket was still around in commit 5f78b1261d2773fe80254f52d2212a0b0f1d0ec1 on the main branch (or otherwise just check some other old commits).
How did you come to the conclusion it was 1808? It seems so specific. I am trying to track down why printing from the app is SO much faster than using the library
@vertgo If you log the data transfer you can see the size of the packets it is sending. Basically it is the size of the payload minus the header (2), length (1), event code (2), checksum (1) and packet index (4). See this post for an example: https://github.com/javl/InstaxBLE/issues/9#issuecomment-1670847484
Making it faster would be amazing, but I haven't figure out how yet :disappointed:
I've created a separate issue for the speed problem, feel free to post any suggestions, test or remarks in there!
Basically it is the size of the payload minus the header (2), length (1), event code (2), checksum (1) and packet index (4)
@javl , isn't the length two (2) bytes ?
Basically it is the size of the payload minus the header (2), length (1), event code (2), checksum (1) and packet index (4)
@javl , isn't the length two (2) bytes ?
You're right, its a big-endian unsigned short to be precise https://github.com/javl/InstaxBLE/blob/f8c405108931ba4dadc74d7fed0ca309ef5f4f94/InstaxBLE.py#L303
I was wondering if the same code can be adapted to the SQUARE Link? https://instax.com/square_link/en/