zabsalahid / serialport-gsm

SerialPort-GSM is a simplified plugin for communicating with gsm modems. (Primarily for sms) (Focused in PDU mode)
MIT License
90 stars 47 forks source link

Ussd support #17

Closed karianpour closed 5 years ago

karianpour commented 5 years ago

Here I made a listeners list which we can inject a listener to perform logic in data received. Then we have a ussd module which use this option to inject it's logic on incoming ussd message from the modem.

Xsmael commented 5 years ago

This feature is awesome but how do you use it? any code example ? Thanks!

karianpour commented 5 years ago

here is my test code, but simplified for readablity:

const serialportgsm = require('../lib/index');
const ussd = require('../lib/functions/ussd')

const options = {...};

const modem = serialportgsm.Modem();
ussd(modem);

modem.on('onNewIncomingUSSD', (data)=>{
  console.log('onNewIncomingUSSD', {data});
});

let command = '*555*1*2#';
r = await modem.sendUSSD(command);

of course you need to change the require path and handle errors as well.

the problem is that you have to handle the command sequence as can have only one USSD session, which does not fit functional async programming paradigm. I guess that we might need a different approach.

Xsmael commented 5 years ago

When I tried your code I get this error:

SyntaxError: await is only valid in async function
    at new Script (vm.js:79:7)
    at createScript (vm.js:251:10)
    at Object.runInThisContext (vm.js:303:10)
    at Module._compile (internal/modules/cjs/loader.js:657:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
    at startup (internal/bootstrap/node.js:283:19)
Xsmael commented 5 years ago

I have changed my code to this :

modem.sendUSSD('*110#').then(
                (success)=>{console.log(success)},
                (fail)=>{console.log(fail)}
                );

now it works i get the answer OK from the modem, but the onNewIncomingUSSD event is never fired

karianpour commented 5 years ago

@Xsmael I though you will figure it out, the code with await should be read as:

async main(){
  let command = '*555*1*2#';
  try{
    let r = await modem.sendUSSD(command);
    console.log(r);
  } catch(err){
    console.error(err);
    // handle the error here
  }
}

main();

for the second part of your problem, it might be the modem behavior, try to debug it as follow:

so you see what the modem reaction is and what data you get. try to figure out the problem.

Xsmael commented 5 years ago

@karianpour

I though you will figure it out, the code with await should be read as: ^^' Sorry i wasnt really familiar with promises

This is the output I get after uncommenting the lines mentionned above:

AT+CMEE=1;+CREG=2
OK

AT+CLIP=1
OK

AT+CUSD=1,"*110#",15
OK

{ status: 'success', request: 'ussd', data: 'OK' }
AT+CSQ
+CSQ: 24,0

OK

+CUSD: 0, "Solde:350.00F.", 15

This is the USSD response +CUSD: 0, "Solde:350.00F.", 15 in particular the string "Solde:350.00F."

so it actually works, I know this, also because when i set the logger from modem option object to console, i see the response in the log.

karianpour commented 5 years ago

So, I guess I can imagine the bug,

in ussd.js line 27 do the following change:

-    if(decodable.length>1){
+   if(decodable && decodable.length>1){

the problem is that the result of let decodable = /\"(.*?)\"/g.exec(splitted_newpart[1]) is null, so the mentioned line will break. Please test it and if it is ok, please make pull request :D or ask me to do it.

Xsmael commented 5 years ago

Hey, all my apologies, i noticed it was a mistake from me, am using a module for logging(and console output aswell); and there was a typo there. that's why I got no output when the event got triggered.

so i noticed it works with both of theses lines. The second one looks more safe though.

    if(decodable.length>1){
   if(decodable && decodable.length>1){

is a PR still necessary?

HOWEVER THERE IS ANOTHER ISSUE: i dont get proper text response

*99# is supposed to return the MSISDN, in a string like this: +CUSD: 0, "MSISDN: 22658945970", 15 where the text is "MSISDN: 22658945970"

but i get this instead, looks like it is truncated

{ status: 'success', request: 'ussd', data: 'OK' }

{ status: 'Incoming USSD',
  data:
   { text: ' "MSISDN:',
     follow: 'no further action required',
     followCode: '0' } }

and for *110# i should get this "Solde:350.00F." but i get some weird stuff instead:

{ status: 'success', request: 'ussd', data: 'OK' }

{ status: 'Incoming USSD',
  data:
   { text: '\u0000\u0000\u0000\u0000',
     follow: 'no further action required',
     followCode: '0' } }
karianpour commented 5 years ago

@Xsmael, I made the PR, also I added a new property to USSD answer, the raw data, after approval you will be able to process the answer in that property.

karianpour commented 5 years ago

@Xsmael PR is merged, let me know if it solved your problem.

Xsmael commented 5 years ago

I don't know if it took into account the files you modified, coz from the file list last modification date changed only for the readme and package files as you can see here:

image

karianpour commented 5 years ago

@Xsmael, I also updated the node modules which had vulnerabillity issues. So don't worry.

umwdeveloper commented 1 year ago

@karianpour I have a problem when I send ussd I get response in which I have to choose one option but I don't want to choose that and I close the modem and redo this process recursively, now the problem is that when the next time the ussd is sent it says invalid choice because that previous session is still open. I closed the modem but ussd session is still open how can I close that?

spidy0x0 commented 1 year ago

@uosdevelopers

AT+CUSD=2 is used to end a USSD session.

 //end session 
    async function endSession() {
        //end previous session
        await modem.executeCommand('AT+CUSD=2', (result, err) => {
            if (err) {
                console.log(`Error - ${err}`);
            } else {
                console.log(`End Session Status ${JSON.stringify(result)}`);
            }
        });

        return true;
    }
spidy0x0 commented 1 year ago

sometimes it brings unexpected responses such as "undefined", etc. if that happens,

// end session
endSession();
// sleep for 2 seconds
await sleep(2000);
//restart for loop
 i = -1;
continue;
umwdeveloper commented 1 year ago

@uosdevelopers

AT+CUSD=2 is used to end a USSD session.

 //end session 
    async function endSession() {
        //end previous session
        await modem.executeCommand('AT+CUSD=2', (result, err) => {
            if (err) {
                console.log(`Error - ${err}`);
            } else {
                console.log(`End Session Status ${JSON.stringify(result)}`);
            }
        });

        return true;
    }

Thanks I was able to fix that